From 5966e29d34e0bab44de8f0a6a8c6f3d9c94e93a2 Mon Sep 17 00:00:00 2001 From: camdenmoors <66680985+camdenmoors@users.noreply.github.com> Date: Wed, 19 Aug 2020 11:35:33 -0400 Subject: [PATCH] Update bootstrap to 4.5.0 (#519) --- .github/workflows/run-tests.yml | 2 +- Gemfile | 8 +- Gemfile.lock | 40 +- README.md | 6 +- app/assets/javascripts/application.js | 6 + app/assets/javascripts/challenges.js.coffee | 2 +- app/assets/javascripts/sticky-footer.js | 2 +- app/assets/javascripts/user.js.coffee | 1 - app/assets/stylesheets/challenges.scss | 23 + .../stylesheets/custom-bootstrap.css.scss | 401 ++++++++++-------- app/assets/stylesheets/team.css.scss | 6 +- app/views/achievements/index.html.haml | 2 +- app/views/challenges/show.html.haml | 18 +- app/views/games/_divisions.html.haml | 2 +- app/views/games/_jeopardy_table.html.haml | 2 +- app/views/games/_legend.html.haml | 4 +- app/views/games/_pentest_game_table.html.haml | 2 +- app/views/games/_team_list.html.haml | 11 +- app/views/games/_team_list_tbody.html.haml | 7 +- .../games/_teams_x_challenges_table.html.haml | 2 +- app/views/games/show.html.haml | 2 +- app/views/games/summary.html.haml | 4 +- app/views/home/index.html.haml | 4 +- app/views/layouts/_dropdown.html.haml | 78 ++-- app/views/layouts/_flash_anchor.html.haml | 2 +- app/views/layouts/_footer.html.haml | 2 +- app/views/layouts/_navbar.html.haml | 40 +- app/views/layouts/application.html.haml | 10 +- app/views/layouts/mailer.text.haml | 2 +- app/views/messages/index.html.haml | 2 +- app/views/teams/_admin_info_table.html.haml | 41 +- .../teams/_challenge_list_tbody.html.haml | 3 +- .../teams/_defensive_points_table.html.haml | 4 +- app/views/teams/_invites_form.html.haml | 10 +- app/views/teams/_invites_table.html.haml | 8 +- app/views/teams/_list.html.haml | 8 +- app/views/teams/_requests_table.html.haml | 6 +- .../teams/_score_adjustments_table.html.haml | 2 +- .../teams/_solved_challenges_table.html.haml | 11 +- app/views/teams/_team_form.html.haml | 33 +- app/views/teams/_team_summary.html.haml | 63 +-- app/views/teams/show.html.haml | 82 ++-- app/views/teams/summary.html.haml | 7 +- app/views/user_mailer/open_source.html.haml | 2 +- .../users/_join_team_invites_table.html.haml | 8 +- .../users/_join_team_requests_table.html.haml | 4 +- app/views/users/join_team.html.haml | 57 +-- app/views/users/passwords/edit.html.haml | 2 +- .../registrations/_delete_user_form.html.haml | 15 +- .../registrations/_update_user_form.html.haml | 28 +- .../users/registrations/_user_form.html.haml | 127 +++--- app/views/users/sessions/new.html.haml | 27 +- .../users/shared/_create_user_link.html.haml | 2 +- .../shared/_reset_your_password.html.haml | 2 +- .../users/shared/_retrieve_access.html.haml | 16 +- config/initializers/application_module.rb | 2 +- config/initializers/customize_error.rb | 11 + config/initializers/obscenity_module.rb | 2 +- config/initializers/paper_trail.rb | 2 +- config/initializers/rails_admin.rb | 1 + config/initializers/user_module.rb | 2 +- config/locales/en.yml | 5 +- .../achievement_display_modes_test.rb | 2 +- .../application_display_modes_test.rb | 4 +- .../integration/summary_display_modes_test.rb | 7 +- test/integration/team_display_modes_test.rb | 19 +- test/integration/user_display_modes_test.rb | 8 +- 67 files changed, 725 insertions(+), 601 deletions(-) create mode 100644 config/initializers/customize_error.rb diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 25c18dc0e..1e5695d36 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -52,7 +52,7 @@ jobs: RAILS_ENV: test run: | bundle exec brakeman -qAzw1 - bundle exec bundle-audit check --update --ignore CVE-2016-10735 CVE-2019-8331 + bundle exec bundle-audit check --update bundle exec rails db:create bundle exec rails test bundle exec rails spellcheck diff --git a/Gemfile b/Gemfile index 01138ed8a..b5090fa0f 100644 --- a/Gemfile +++ b/Gemfile @@ -5,14 +5,15 @@ source 'https://rubygems.org' gem 'activerecord-precounter' gem 'awesome_nested_fields' gem 'bootsnap', '>= 1.1.0', require: false -gem 'bootstrap-kaminari-views' -gem 'bootstrap-sass', '~> 2.3.2.2' +gem 'bootstrap', '~> 4.5.0' +gem 'bootstrap4-kaminari-views' gem 'carrierwave-postgresql', '< 0.3.0' # Can be upgraded once https://github.com/diogob/carrierwave-postgresql/issues/33 gem 'chartkick' gem 'delayed_job' gem 'delayed_job_active_record' gem 'devise' gem 'filterrific' +gem 'font-awesome-rails' gem 'formtastic' gem 'geocoder' gem 'groupdate' @@ -27,6 +28,7 @@ gem 'paper_trail' gem 'paper_trail-association_tracking' gem 'passenger', require: 'phusion_passenger/rack_handler' gem 'pg' +gem 'popper_js', '~> 1.14.5' gem 'prawn' gem 'rails', '~> 6.0.2' gem 'rails_admin' @@ -61,7 +63,7 @@ group :assets do gem 'coffee-rails' gem 'sass-rails' # See https://github.com/sstephenson/execjs#readme for more supported runtimes - gem 'therubyracer', platforms: :ruby + gem 'mini_racer', platforms: :ruby gem 'uglifier' end diff --git a/Gemfile.lock b/Gemfile.lock index 1d0cf9f9e..8d39f896d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,16 +65,20 @@ GEM addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) ast (2.4.1) + autoprefixer-rails (9.8.6.1) + execjs awesome_nested_fields (0.6.4) rails (>= 3.0.0) - bcrypt (3.1.13) + bcrypt (3.1.15) bootsnap (1.4.8) msgpack (~> 1.0) - bootstrap-kaminari-views (0.0.5) + bootstrap (4.5.2) + autoprefixer-rails (>= 9.1.0) + popper_js (>= 1.14.3, < 2) + sassc-rails (>= 2.0.0) + bootstrap4-kaminari-views (1.0.1) kaminari (>= 0.13) rails (>= 3.1) - bootstrap-sass (2.3.2.2) - sass (~> 3.2) brakeman (4.9.0) builder (3.2.4) bundler-audit (0.7.0.1) @@ -96,7 +100,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.6) + concurrent-ruby (1.1.7) crass (1.0.6) delayed_job (4.1.8) activesupport (>= 3.0, < 6.1) @@ -126,6 +130,8 @@ GEM ffi-hunspell (0.5.0) ffi (~> 1.0) filterrific (5.2.1) + font-awesome-rails (4.7.0.5) + railties (>= 3.2, < 6.1) formtastic (3.1.5) actionpack (>= 3.2.13) geocoder (1.6.3) @@ -177,7 +183,7 @@ GEM addressable (~> 2.7) letter_opener (1.7.0) launchy (~> 2.2) - libv8 (3.16.14.19) + libv8 (8.4.255.0) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -195,6 +201,8 @@ GEM mimemagic (0.3.5) mini_mime (1.0.2) mini_portile2 (2.4.0) + mini_racer (0.3.1) + libv8 (~> 8.4.255) minitest (5.14.1) msgpack (1.3.3) multipart-post (2.1.1) @@ -216,6 +224,7 @@ GEM rake (>= 0.8.1) pdf-core (0.8.1) pg (1.2.3) + popper_js (1.14.7) prawn (2.3.0) pdf-core (~> 0.8.1) ttfunk (~> 1.6) @@ -281,7 +290,6 @@ GEM ffi (~> 1.0) recaptcha (5.5.0) json - ref (2.0.0) regexp_parser (1.7.1) remotipart (1.4.4) request_store (1.5.0) @@ -309,11 +317,6 @@ GEM ruby_parser (3.14.2) sexp_processor (~> 4.9) rubyzip (2.3.0) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) @@ -342,9 +345,6 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) temple (0.8.2) - therubyracer (0.12.3) - libv8 (~> 3.16.14.15) - ref thor (1.0.1) thread_safe (0.3.6) tilt (2.0.10) @@ -356,7 +356,7 @@ GEM unicode-display_width (1.7.0) warden (1.2.8) rack (>= 2.0.6) - websocket-driver (0.7.2) + websocket-driver (0.7.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) zeitwerk (2.4.0) @@ -368,8 +368,8 @@ DEPENDENCIES activerecord-precounter awesome_nested_fields bootsnap (>= 1.1.0) - bootstrap-kaminari-views - bootstrap-sass (~> 2.3.2.2) + bootstrap (~> 4.5.0) + bootstrap4-kaminari-views brakeman bundler-audit carrierwave-postgresql (< 0.3.0) @@ -382,6 +382,7 @@ DEPENDENCIES faker ffi-hunspell filterrific + font-awesome-rails formtastic geocoder groupdate @@ -393,11 +394,13 @@ DEPENDENCIES kramdown letter_opener listen + mini_racer obscenity paper_trail paper_trail-association_tracking passenger pg + popper_js (~> 1.14.5) prawn pry-remote rails (~> 6.0.2) @@ -411,7 +414,6 @@ DEPENDENCIES scout_apm sentry-raven simplecov - therubyracer uglifier BUNDLED WITH diff --git a/README.md b/README.md index 58b957707..220e2fd5a 100644 --- a/README.md +++ b/README.md @@ -35,15 +35,15 @@ If the project is being hosted on Heroku a daily task can be created using the H #### Gameboard -![gameboard](https://i.imgur.com/UgkPX5q.png) +![gameboard](https://i.imgur.com/9NkEPac.png) #### Administration Dashboard -![admin dashboard](https://i.imgur.com/lzj7U3m.png) +![admin dashboard](https://i.imgur.com/T9Fth6g.png) #### Administration Dashboard -> Add challenge -![add challenge](https://i.imgur.com/ZRyimTp.png) +![add challenge](https://i.imgur.com/kjkZ1pI.png) ##### More screenshots available on the [wiki](https://github.com/mitre-cyber-academy/ctf-scoreboard/wiki/Screenshots). diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 7b704463c..ff83ed6dd 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,9 +11,11 @@ // GO AFTER THE REQUIRES BELOW. // //= require jquery +//= require jquery_ujs //= require_tree . //= require jquery.nested-fields // Loads all Bootstrap javascripts +//= require popper //= require bootstrap //= require filterrific/filterrific-jquery //= require highcharts @@ -22,3 +24,7 @@ $(function () { $('[data-toggle="tooltip"]').tooltip() }) + +var submitUserForm = function () { + document.getElementById("user-form").submit(); +}; diff --git a/app/assets/javascripts/challenges.js.coffee b/app/assets/javascripts/challenges.js.coffee index c1e8df921..5e0118663 100644 --- a/app/assets/javascripts/challenges.js.coffee +++ b/app/assets/javascripts/challenges.js.coffee @@ -5,7 +5,7 @@ $(document).ready -> $('.toggler').click (e) -> + $('#hiddenUntilToggle').toggleClass("d-none") e.preventDefault() - $('.hide').toggle() return return diff --git a/app/assets/javascripts/sticky-footer.js b/app/assets/javascripts/sticky-footer.js index d438ed4ac..adf1dca3e 100644 --- a/app/assets/javascripts/sticky-footer.js +++ b/app/assets/javascripts/sticky-footer.js @@ -1,5 +1,5 @@ var stick = function () { - $('body').css('margin-bottom', $('#page-footer').height() + 40); + $('body').css('margin-bottom', $('#page-footer').height() + 60); } $(document).ready(function () { stick(); diff --git a/app/assets/javascripts/user.js.coffee b/app/assets/javascripts/user.js.coffee index ec5feac26..547480332 100644 --- a/app/assets/javascripts/user.js.coffee +++ b/app/assets/javascripts/user.js.coffee @@ -1,5 +1,4 @@ window.runOnPageLoad = () -> - $('input[type=file]').bootstrapFileInput() if $('#user_state').val() == "NA" or $('#user_year_in_school').val() == "0" $('#compete-for-prizes').hide() $('#user_compete_for_prizes').prop("checked", false) diff --git a/app/assets/stylesheets/challenges.scss b/app/assets/stylesheets/challenges.scss index 12faae8c0..56b14c67c 100644 --- a/app/assets/stylesheets/challenges.scss +++ b/app/assets/stylesheets/challenges.scss @@ -1,3 +1,26 @@ // Place all the styles related to the challenges controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ + +@media (max-device-width: 767px) { + .container { + max-width: 100% !important; + margin-right: 0 !important; + margin-left: 0 !important; + } + + h1 { + margin-right: auto; + margin-left: 1em; + } + + nav { + margin-right: -2%; + margin-left: auto; + } + + footer { + margin-right: auto; + margin-left: auto; + } +} diff --git a/app/assets/stylesheets/custom-bootstrap.css.scss b/app/assets/stylesheets/custom-bootstrap.css.scss index f47ed6860..cad50034f 100644 --- a/app/assets/stylesheets/custom-bootstrap.css.scss +++ b/app/assets/stylesheets/custom-bootstrap.css.scss @@ -1,132 +1,156 @@ + $btnPrimaryBackground: #5d8cb6; $btnPrimaryBackgroundHighlight: #39546c; +$blue: #4f7698; @import "bootstrap"; -body { padding-top: 60px; } -@import "bootstrap-responsive"; - +@import "font-awesome"; .breadcrumb { - text-align:left; - background: #2A5192; - filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#0A2C641E, endColorstr=#0A2C641E); - /* For IE 8*/ - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#0A2C641E, endColorstr=#0A2C641E)"; - background-color: rgba(10, 44, 100,0.3); + text-align: left; + background: #2A5192; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#0A2C641E, endColorstr=#0A2C641E); + /* For IE 8*/ + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#0A2C641E, endColorstr=#0A2C641E)"; + background-color: rgba(10, 44, 100, 0.3); } td.break-word { - max-width: 100px; - @extend .break-word; + max-width: 100px; + @extend .break-word; } td.text-center { - text-align: center; + text-align: center; } th.text-center { - text-align: center; + text-align: center; } .break-word { - line-height: normal; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + line-height: normal; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -.remove_top_padding { - margin-top:-20px; -} .control-label-required { - @extend .control-label; - font-weight:bold; + font-weight: bold; } + .control-label-required:before { content: "* "; - color:red; + color: red; } + .disclaimer { color: gray; } + td form { - margin: 0 0 0 0; + margin: 0 0 0 0; } + .alert { - ul, ol { margin: 5px 0 5px 12px;} - li {list-style-type: none;} - li:before {content: " - ";} + ul, + ol { + margin: 5px 0 5px 12px; + } + li { + list-style-type: none; + } + li:before { + content: " - "; + } } + .field_with_errors { - color: red; - display: inline; + color: red; + display: inline; } + .jumbotron { - position: relative; - color: #fff; - text-align: center; - text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075); - background: #476988; /* Old browsers */ - background: rgb(71, 105, 136); - background: -moz-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); - background: -webkit-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); - background: -o-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); - background: -ms-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); - background: linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#446582', endColorstr='#5D8CB6',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ - -webkit-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); - -moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); - box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); + position: relative; + color: #fff; + text-align: center; + border-top-left-radius: 0rem; + border-top-right-radius: 0rem; + border-bottom-right-radius: 0rem; + border-bottom-left-radius: 0rem; + text-shadow: 0 1px 3px rgba(0, 0, 0, .4), 0 0 30px rgba(0, 0, 0, .075); + background: #476988; + /* Old browsers */ + background: rgb(71, 105, 136); + background: -moz-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); + background: -webkit-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); + background: -o-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); + background: -ms-linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); + background: linear-gradient(0deg, rgb(68, 101, 130) 30%, rgb(93, 140, 182) 70%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#446582', endColorstr='#5D8CB6', GradientType=1); + /* IE6-9 fallback on horizontal gradient */ + -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2); + -moz-box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2); + box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2); } + .corporate { - background: #3F7D13; /* Old browsers */ - background: rgb(63, 125, 19); - background: -moz-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); - background: -webkit-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); - background: -o-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); - background: -ms-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); - background: linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2A6D00', endColorstr='#5D932F',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ + background: #3F7D13; + /* Old browsers */ + background: rgb(63, 125, 19); + background: -moz-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); + background: -webkit-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); + background: -o-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); + background: -ms-linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); + background: linear-gradient(0deg, rgb(42, 109, 0) 30%, rgb(93, 147, 47) 70%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2A6D00', endColorstr='#5D932F', GradientType=1); + /* IE6-9 fallback on horizontal gradient */ } + .jumbotron h1 { - font-size: 80px; - font-weight: bold; - letter-spacing: -1px; - line-height: 1; + font-size: 80px; + font-weight: bold; + letter-spacing: -1px; + line-height: 1; } + .jumbotron p { - font-size: 24px; - font-weight: 300; - line-height: 30px; - margin-bottom: 30px; + font-size: 24px; + font-weight: 300; + line-height: 30px; + margin-bottom: 30px; } + /* Link styles (used on .masthead-links as well) */ + .jumbotron a { - color: #fff; - color: rgba(255,255,255,.5); - -webkit-transition: all .2s ease-in-out; - -moz-transition: all .2s ease-in-out; - transition: all .2s ease-in-out; + color: #fff; + color: rgba(255, 255, 255, .5); + -webkit-transition: all .2s ease-in-out; + -moz-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; } + .jumbotron a:hover { - color: #fff; - text-shadow: 0 0 10px rgba(255,255,255,.25); + color: #fff; + text-shadow: 0 0 10px rgba(255, 255, 255, .25); } + .btn-corporate { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #37A037; - *background-color: #51a351; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#37A837), to(#388138)); - background-image: -webkit-linear-gradient(top, #37A837, #388138); - background-image: -o-linear-gradient(top, #37A837, #388138); - background-image: linear-gradient(to bottom, #37A837, #388138); - background-image: -moz-linear-gradient(top, #37A837, #388138); - background-repeat: repeat-x; - border-color: #388138 #388138 #37A837; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #37A037; + *background-color: #51a351; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#37A837), to(#388138)); + background-image: -webkit-linear-gradient(top, #37A837, #388138); + background-image: -o-linear-gradient(top, #37A837, #388138); + background-image: linear-gradient(to bottom, #37A837, #388138); + background-image: -moz-linear-gradient(top, #37A837, #388138); + background-repeat: repeat-x; + border-color: #388138 #388138 #37A837; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-corporate:hover, @@ -134,176 +158,217 @@ td form { .btn-corporate.active, .btn-corporate.disabled, .btn-corporate[disabled] { - color: #ffffff; - background-color: #388138; - *background-color: #007C33; + color: #ffffff; + background-color: #388138; + *background-color: #007C33; } .btn-corporate:active, .btn-corporate.active { - background-color: #408140 \9; + background-color: #408140 \9; } + .btn-width { - width:100px; + width: 100px; } -.catchphrase h1 { + +.catchphrase h1 { color: #5A5A5A; - margin-bottom:10px; - padding-bottom:10px; - text-align:left; + margin-bottom: 10px; + padding-bottom: 10px; + text-align: left; font-size: 32px; border-bottom: 1px solid #EEE; } -#get-started h1 -{ - text-align:center; - font-size:40px; - border-bottom:0; - padding-bottom:45px; + +#get-started h1 { + text-align: center; + font-size: 40px; + border-bottom: 0; + padding-bottom: 45px; } -.catchphrase h2 { + +.catchphrase h2 { color: #5A5A5A; - padding-bottom:10px; - text-align:left; - font-size:26px; + padding-bottom: 10px; + text-align: left; + font-size: 26px; border-bottom: 1px solid #EEE; } + .catchphrase h3 { color: #5A5A5A; font-weight: normal; font-size: 28px; border-bottom: 1px solid #EEE; } + .centerbutton { - display:inline-block; + display: inline-block; } + .colored-divider { - background-color: #b8d12f; - min-height:20px; - margin-bottom:20px; + margin-top: -35px; + background-color: #b8d12f; + min-height: 20px; + margin-bottom: 20px; } + .directions h3 { - font-weight:normal; + font-weight: normal; color: #5A5A5A; } + .directions { - padding-left:10px; + padding-left: 10px; } + .maincontent h2 { color: #5A5A5A; - font-weight:normal; + font-weight: normal; font-size: 28px; } + .maincontent p { - text-align:left; + text-align: left; } + .maincontent img { - height:125px; + height: 125px; } + .maincontent { - margin-bottom:40px; + margin-bottom: 40px; border-bottom: 1px solid #EEE; } + .maincontent .span4 { - padding-bottom:30px; + padding-bottom: 30px; } + .no-bottom-border { - border-bottom:0; + border-bottom: 0; } + .top-border { - margin-top:20px; - padding-top:10px; - border-top:1px solid #EEE; + margin-top: 20px; + padding-top: 10px; + border-top: 1px solid #EEE; } + .subheading { font-size: 16px; } + .space-text-from-input { - padding-left:20px; + padding-left: 20px; } + .footer.well { - margin-bottom:0px; + margin-bottom: 0px; color: #5A5A5A; - bottom:0; + bottom: 0; } + #subpage { - padding: 40px 0; + padding: 40px 0; } + #subpage h1 { - text-align:left; - font-size:50px; + text-align: left; + font-size: 50px; } + #subpage p { - text-align:left; - font-size:20px; - padding-right:190px; + text-align: left; + font-size: 20px; + padding-right: 190px; } + .hasheadimg h1 { - padding-top:19px; + padding-top: 19px; } + .label-custom { - font-weight:bold; - margin-left:180px; - margin-bottom:20px; + font-weight: bold; + margin-bottom: 20px; +} + +#legend { + border-left: .25em solid #eee; +} + +#legendContent { + margin-left: 1em; } + .media .pull-left { - margin-right:15px; + margin-right: 15px; } + .media { - margin-bottom:20px; - min-height:150px /*Make sure to change this if the thumbnail size changes for media */ + margin-bottom: 20px; + min-height: 150px/*Make sure to change this if the thumbnail size changes for media */ } -.media h4 -{ + +.media h4 { color: #5A5A5A; font-size: 20px; } + .noborderbottom { - border:none; + border: none; } + .well-small { - min-height:10px; + min-height: 10px; } -@media (max-width: 767px) { + +.white { + color: #fff; +} + +@media (max-device-width: 767px) { .bigheader { - display:none; + display: none; } #subpage h1 { - font-size:30px; - padding-left:22px; + font-size: 30px; + padding-left: 22px; } #subpage p { - font-size:16px; - padding-left:22px; - padding-right:22px; + font-size: 16px; + padding-left: 22px; + padding-right: 22px; + } + .btn-large { + padding: 4px 12px; + font-size: 14px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } - .btn-large { - padding: 4px 12px; - font-size: 14px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - } - .colored-divider { - margin-right: -20px; - margin-left: -20px; - } - .jumbotron { - margin-right: -20px; + .colored-divider { + margin-right: -20px; margin-left: -20px; - } - #page-footer { - margin-left: -20px; - } + } + .jumbotron { + margin-right: -20px; + margin-left: -20px; + } + #page-footer { + margin-left: -20px; + } } + @media (max-width: 480px) { - .label-custom { - margin-left:0px; - margin-bottom:20px; - } - .btn-large { - padding: 3px 9px !important; - font-size: 12px !important; - line-height: 18px !important; - } + .label-custom { + margin-left: 0px; + margin-bottom: 20px; + } + .btn-large { + padding: 3px 9px !important; + font-size: 12px !important; + line-height: 18px !important; + } } diff --git a/app/assets/stylesheets/team.css.scss b/app/assets/stylesheets/team.css.scss index 47200b4cf..a1b5e5c12 100644 --- a/app/assets/stylesheets/team.css.scss +++ b/app/assets/stylesheets/team.css.scss @@ -2,5 +2,7 @@ // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ - - +// Make FontAwesome black by default on the user table +table#usertable i.fa { + color: black; +} diff --git a/app/views/achievements/index.html.haml b/app/views/achievements/index.html.haml index 1e51fec9c..f3bd7128c 100644 --- a/app/views/achievements/index.html.haml +++ b/app/views/achievements/index.html.haml @@ -3,7 +3,7 @@ - if @achievements.count == 0 %h4.zero-items-text= t('achievements.index.zero_items_text') - else - %table.table.table-bordered.table-striped + %table.table.table-bordered.table-striped.table-hover %thead %tr %th= t('achievements.index.table_header_achievement_name') diff --git a/app/views/challenges/show.html.haml b/app/views/challenges/show.html.haml index c7b3391b9..a6fe1bf7a 100644 --- a/app/views/challenges/show.html.haml +++ b/app/views/challenges/show.html.haml @@ -1,7 +1,7 @@ -# For PentestGames, @challenge here can actually be a flag object since Pentest challenges belong to teams + challenges and are linked by a flag object. -# - content_for :admin_menu do - %li= link_to t('challenges.admin_edit_challenge', challengename: @challenge.name), admin_edit_url(@challenge) + %a.dropdown-item{:href => admin_edit_url(@challenge)}= t('challenges.admin_edit_challenge', challengename: @challenge.name) - content_for :header do = @challenge.name @@ -23,23 +23,21 @@ %div#sponsorInfo{ :style => "margin-bottom:40px;" } %h3#sponsorName= t('challenges.show.sponsor') - unless @challenge.sponsor_logo.empty? - = image_tag(@challenge.sponsor_logo, :id => "sponsorLogo") + = image_tag(@challenge.sponsor_logo, :id => "sponsorLogo", :class => "w-25") - unless @challenge.sponsor_description.empty? = sanitize(Kramdown::Document.new(@challenge.sponsor_description).to_html) - if @solvable - = form_for :challenge, url: submit_url(@defense_team, @challenge), method: "put", html: { class: "well", style: "margin-bottom:40px;" } do |f| - .control-group - %p - = t('challenges.submit_flag') - .control-group - .controls - = f.text_field :submitted_flag, :class => "span5" + = form_for :challenge, url: submit_url(@defense_team, @challenge), method: "put", html: { class: "card card-body bg-light", style: "margin-bottom:40px;" } do |f| + .form-group + .col-xs-2 + = f.label t('challenges.submit_flag') + = f.text_field :submitted_flag, :class => "form-control col-sm-10" .control-group = invisible_recaptcha_tags text: 'Submit', :class => "btn btn-primary" - if @solved_by.length > 0 - %table.table.table-bordered.table-striped + %table.table.table-bordered.table-striped.table-hover %thead %tr %th # diff --git a/app/views/games/_divisions.html.haml b/app/views/games/_divisions.html.haml index fd1e0841d..f5710ca70 100644 --- a/app/views/games/_divisions.html.haml +++ b/app/views/games/_divisions.html.haml @@ -4,7 +4,7 @@ %ul.nav.nav-tabs#summaryTabs - divisions.each do |d| %li{ :class => ('active' if active_division.eql? d) } - = link_to "#{d.name}", "#division-#{d.id}-tab", "data-toggle"=>"tab" + = link_to "#{d.name}", "#division-#{d.id}-tab", "data-toggle"=>"tab", :class => 'nav-link text-dark' .tab-content - divisions.each do |d| .tab-pane{ :class => ('active' if active_division.eql? d), :id => "division-#{d.id}-tab" } diff --git a/app/views/games/_jeopardy_table.html.haml b/app/views/games/_jeopardy_table.html.haml index ab92c6350..817c9a1ac 100644 --- a/app/views/games/_jeopardy_table.html.haml +++ b/app/views/games/_jeopardy_table.html.haml @@ -1,4 +1,4 @@ -%table.table.table-bordered.table-bolded#jeopardy-table +%table.table.table-bordered.table-bolded.table-hover#jeopardy-table %thead %tr - @category_ids.each do |category| diff --git a/app/views/games/_legend.html.haml b/app/views/games/_legend.html.haml index 1ae84939e..78e56c741 100644 --- a/app/views/games/_legend.html.haml +++ b/app/views/games/_legend.html.haml @@ -1,6 +1,6 @@ %h3= t('game.legend.legend_name') -%blockquote - %p{style: "font-size: 1rem;"} +%blockquote.blockquote#legend + %p#legendContent{style: "font-size: 1rem;"} %b{style: "color:#006600;"} = t('game.legend.dark_green') = t('game.legend.dark_green_desc') diff --git a/app/views/games/_pentest_game_table.html.haml b/app/views/games/_pentest_game_table.html.haml index 57cee4d87..fd06b0f0d 100644 --- a/app/views/games/_pentest_game_table.html.haml +++ b/app/views/games/_pentest_game_table.html.haml @@ -1,5 +1,5 @@ %h3=I18n.t('game.attack_defend_challenges') -%table.table.table-bordered.table-bolded#pentest-table +%table.table.table-bordered.table-bolded.table-hover#pentest-table %thead %tr - @pentest_table_heading.each do |challenge| diff --git a/app/views/games/_team_list.html.haml b/app/views/games/_team_list.html.haml index 94f5f70a0..1ced27625 100644 --- a/app/views/games/_team_list.html.haml +++ b/app/views/games/_team_list.html.haml @@ -2,7 +2,7 @@ %h4.zero-items-text= t('teams.summary.zero_teams_text') - else - max = 0 - %table.table.table-bordered.table-striped + %table.table.table-bordered.table-striped.table-hover %thead %tr %th{ :style => "width:50px;" } # @@ -13,13 +13,14 @@ / Get the first teams score and use that as the full score bar - max_score = teams.first.current_score / We pass in starting_rank here to start the list at the proper index - = render partial: 'games/team_list_tbody', locals: { teams: teams.slice(0..4), starting_rank: 1, max_score: max_score } + = render partial: 'games/team_list_tbody', locals: { teams: teams.slice(0..5), starting_rank: 1, max_score: max_score } / This part of the list is hidden until the user clicks the 'Show/Hide Teams' button below = render partial: 'games/team_list_tbody', locals: { | - teams: teams.slice(5..), | - starting_rank: 6, | + teams: teams.slice(6..), | + starting_rank: 7, | max_score: max_score, | - tbody_class: 'hide' | + tbody_id: 'hiddenUntilToggle', | + tbody_class: 'd-none' | } | - if teams.count > 5 %tr diff --git a/app/views/games/_team_list_tbody.html.haml b/app/views/games/_team_list_tbody.html.haml index 7d4e5d9dd..541419afa 100644 --- a/app/views/games/_team_list_tbody.html.haml +++ b/app/views/games/_team_list_tbody.html.haml @@ -1,6 +1,7 @@ - tbody_class ||= '' +- tbody_id ||= '' -%tbody{class: tbody_class} +%tbody{class: tbody_class, id: tbody_id} - teams&.each&.with_index(starting_rank) do |t, i| - score = t.current_score - percent = score.to_f / max_score.to_f * 100.0 @@ -10,5 +11,5 @@ %td= t.achievements.size %td= score %td - .progress{ :style => "margin:0;" } - .bar{ :style => "width:#{percent}%;" } + .progress{ :style => "margin:0; height:20px;" } + .progress-bar{ :style => "width:#{percent}%;" } diff --git a/app/views/games/_teams_x_challenges_table.html.haml b/app/views/games/_teams_x_challenges_table.html.haml index a076fb752..48a3d95b5 100644 --- a/app/views/games/_teams_x_challenges_table.html.haml +++ b/app/views/games/_teams_x_challenges_table.html.haml @@ -1,4 +1,4 @@ -%table.table.table-bordered.table-bolded#teams-x-challenges-table +%table.table.table-bordered.table-bolded.table-hover#teams-x-challenges-table %thead %tr - @headings.each do |challenge| diff --git a/app/views/games/show.html.haml b/app/views/games/show.html.haml index d0cb9eede..50417bbc4 100644 --- a/app/views/games/show.html.haml +++ b/app/views/games/show.html.haml @@ -5,7 +5,7 @@ %h4.zero-items-text= t('game.show.no_challenges') - else -# Render based on the user selected gameboard layout - = render partial: "games/#{@game.board_layout}_table" + #challengeTable= render partial: "games/#{@game.board_layout}_table" - unless @pentest_challenges.empty? %hr -# Always render PentestChallenges. This provides us with the ability to diff --git a/app/views/games/summary.html.haml b/app/views/games/summary.html.haml index f599f125f..c7b318f72 100644 --- a/app/views/games/summary.html.haml +++ b/app/views/games/summary.html.haml @@ -1,13 +1,13 @@ - content_for :header do = t('game.summary.header') -%h3.muted +%h3.text-muted = t('game.summary.teams_summary') %br/ = render partial: "games/divisions", locals: { divisions: @game.divisions, active_division: @active_division} %hr / Only show the flags per hour count when we have more than 1 datapoint to show - if @flags_per_hour.count > 1 - %h3.muted + %h3.text-muted = t('teams.summary.flag_submissions_header') = line_chart @line_chart_data, colors: ['#b8d12f', '#00abca'] diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 8432755ef..bc4f9bf48 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -26,7 +26,7 @@ - unless @game.after_competition? - if user_signed_in? .btn-toolbar - .pagination-centered + .pagination-centered.mx-auto - if current_user.on_a_team? .btn-group = link_to t('home.index.join_team'), team_path(current_user.team_id), :class => "btn btn-large btn-primary" @@ -37,6 +37,6 @@ = link_to t('home.index.create_team'), new_team_path, :class => "btn btn-large btn-primary" - elsif @game.registration_enabled .btn-toolbar - .pagination-centered + .pagination-centered.mx-auto .btn-group = link_to t('home.index.register'), new_user_registration_path, :class => "btn btn-large btn-primary" diff --git a/app/views/layouts/_dropdown.html.haml b/app/views/layouts/_dropdown.html.haml index b44a5c238..4ba6ab859 100644 --- a/app/views/layouts/_dropdown.html.haml +++ b/app/views/layouts/_dropdown.html.haml @@ -1,45 +1,39 @@ -%ul.nav.pull-right +%li.nav-item.dropdown - if user_signed_in? - %li.dropdown - %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"} - = greeting_for_dropdown(current_user) - %b.caret - %ul.dropdown-menu - %li - - if current_user.admin? - = link_to t('application.admin.dashboard'), rails_admin_path - %li.divider - %li= link_to t('application.admin.post_message'), rails_admin.new_path("message") - %li= link_to t('application.admin.view_submitted_flags'), rails_admin.index_path("submitted_flag") - %li= link_to t('application.admin.award_achievement'), rails_admin.new_path("achievement") - %li= link_to t('application.admin.create_score_adjustment'), rails_admin.new_path("score_adjustment") - - if content_for?(:admin_menu) - %li.divider - = yield :admin_menu - - elsif current_user.on_a_team? - = link_to t('home.index.view_team'), team_path(current_user.team_id) - - if current_user.team_captain? - = link_to t('home.index.edit_team'), edit_team_path(current_user.team_id) - - else - = link_to t('home.index.join_team'), join_team_users_path - = link_to t('home.index.create_team'), new_team_path - %li.divider - %li - = link_to t('application.edit_account'), edit_user_registration_path, :method => :get - = link_to t('application.log_out'), destroy_user_session_path, :method => :delete + %a#navbarDropdown.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :style => "color: #fff",:href => "#", :role => "button"} + = greeting_for_dropdown(current_user) + .dropdown-menu.dropdown-menu-right{"aria-labelledby" => "navbarDropdown"} + - if current_user.admin? + %a.dropdown-item{:href => rails_admin_path}= t('application.admin.dashboard') + .dropdown-divider + %a.dropdown-item{:href => rails_admin.new_path("message")}= t('application.admin.post_message') + %a.dropdown-item{:href => rails_admin.index_path("submitted_flag")}= t('application.admin.view_submitted_flags') + %a.dropdown-item{:href => rails_admin.index_path("achievement")}= t('application.admin.award_achievement') + %a.dropdown-item{:href => rails_admin.index_path("score_adjustment")}= t('application.admin.create_score_adjustment') + - if content_for?(:admin_menu) + .dropdown-divider + = yield :admin_menu + .dropdown-divider + - elsif current_user.on_a_team? + %a.dropdown-item{:href => team_path(current_user.team_id)}= t('home.index.view_team') + - if current_user.team_captain? + %a.dropdown-item{:href => edit_team_path(current_user.team_id)}= t('home.index.edit_team') + .dropdown-divider + - else + %a.dropdown-item{:href => join_team_users_path}= t('home.index.join_team') + %a.dropdown-item{:href => new_team_path}= t('home.index.create_team') + .dropdown-divider + %a.dropdown-item{:href => edit_user_registration_path}= t('application.edit_account') + %a.dropdown-item{:href => destroy_user_session_path, "data-method" => :delete}= t('application.log_out') - else - unless @game.nil? - %li.dropdown - %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"} - - if @game.registration_enabled - = t('home.index.login_or_register') - - else - = t('home.index.login') - %b.caret - %ul.dropdown-menu - %li - =link_to t('application.log_in'), new_user_session_path - - if @game.registration_enabled - %li.divider - %li - =link_to t('home.index.register'), new_user_registration_path + %a#navbarDropdown.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :style => "color: #fff",:href => "#", :role => "button"} + - if @game.registration_enabled + = t('home.index.login_or_register') + - else + = t('home.index.login') + .dropdown-menu{"aria-labelledby" => "navbarDropdown"} + %a.dropdown-item{:href => new_user_session_path}= t('application.log_in') + - if @game.registration_enabled + .dropdown-divider + %a.dropdown-item{:href => new_user_registration_path}= t('home.index.register') diff --git a/app/views/layouts/_flash_anchor.html.haml b/app/views/layouts/_flash_anchor.html.haml index 1c512259f..b5b42bf46 100644 --- a/app/views/layouts/_flash_anchor.html.haml +++ b/app/views/layouts/_flash_anchor.html.haml @@ -3,7 +3,7 @@ %a.close{"data-dismiss" => "alert", :href => "#"} × = notice - if !flash[:alert].blank? - .alert.alert-error + .alert.alert-danger %a.close{"data-dismiss" => "alert", :href => "#"} × - if alert.is_a?(Enumerable) = amount_of_errors(alert) diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml index 4a678f012..f4622804f 100644 --- a/app/views/layouts/_footer.html.haml +++ b/app/views/layouts/_footer.html.haml @@ -1,6 +1,6 @@ .container .row-fluid - %p.pull-right + %p.float-right %a{:href => "#"} = t('home.index.back_to_top') %p diff --git a/app/views/layouts/_navbar.html.haml b/app/views/layouts/_navbar.html.haml index 4368eb86d..0c4720544 100644 --- a/app/views/layouts/_navbar.html.haml +++ b/app/views/layouts/_navbar.html.haml @@ -1,20 +1,22 @@ -%a.btn.btn-navbar{"data-target" => ".nav-collapse", "data-toggle" => "collapse"} - %span.icon-bar - %span.icon-bar - %span.icon-bar -= link_to(organization_for_navbar(@game), '/', class: 'brand') -.nav-collapse.collapse - - if @game - %ul.nav - %li{:class => active_navbar?(game_path) } - = always_link_to_if_admin(!@game.before_competition?, t('application.navbar.challenges'), game_path){} - %li{:class => active_navbar?(game_messages_path) } - = link_to(game_messages_path) do +%nav.navbar.navbar-expand-lg.navbar-dark.bg-dark + %a.navbar-brand{:href => "/"}= organization_for_navbar(@game) + %button.navbar-toggler{"aria-controls" => "navbarSupportedContent", "aria-expanded" => "false", "aria-label" => "Toggle navigation", "data-target" => "#navbarSupportedContent", "data-toggle" => "collapse", :type => "button"} + %span.navbar-toggler-icon + #navbarSupportedContent.collapse.navbar-collapse.justify-content-between + %ul.navbar-nav + %li.nav-item + %a.nav-link{:href => game_path, :class => active_navbar?(game_path)}= t('application.navbar.challenges') + %li.nav-item + %a.nav-link{:href => game_messages_path, :class => active_navbar?(game_messages_path)} = t('application.navbar.messages') - %span.badge.badge-important= unread_messages(@unread_message_count) - %li{:class => active_navbar?(game_achievements_path) } - = always_link_to_if_admin(!@game.before_competition?, t('application.navbar.achievements'), game_achievements_path){} - %li{:class => active_navbar?(game_summary_path) } - = always_link_to_if_admin(!@game.before_competition?, t('application.navbar.summary'), game_summary_path){} - %li - = link_to_unless(@game.contact_url.blank?, t('application.navbar.contact'), @game.contact_url, target: '_blank'){} + %span.badge.badge-pill.badge-info= unread_messages(@unread_message_count) + %li.nav-item + %a.nav-link{:href => game_achievements_path, :class => active_navbar?(game_achievements_path)}= t('application.navbar.achievements') + %li.nav-item + %a.nav-link{:href => game_summary_path, :class => active_navbar?(game_summary_path)}= t('application.navbar.summary') + - unless @game.nil? + - unless @game.contact_url.nil? + %li.nav-item + %a.nav-link{:href => @game.contact_url}= t('application.navbar.contact') + %ul.nav.navbar-nav + = render partial: 'layouts/dropdown' diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 1998d678e..9bcd45030 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -6,12 +6,8 @@ = javascript_include_tag "application" = csrf_meta_tags %body - .navbar.navbar-fixed-top.navbar-inverse - .navbar-inner - .container - = render partial: 'layouts/navbar' - = render partial: 'layouts/dropdown' - %header#subpage.jumbotron.masthead.remove_top_padding + = render partial: 'layouts/navbar' + %header#subpage.jumbotron.masthead .container %h1 = yield :header @@ -24,5 +20,5 @@ = render partial: 'layouts/flash_anchor' .container = yield - %footer#page-footer.well.footer + %footer#page-footer.card.card-body.bg-light.footer = render partial: 'layouts/footer' diff --git a/app/views/layouts/mailer.text.haml b/app/views/layouts/mailer.text.haml index f1d0cc898..0a90f092c 100644 --- a/app/views/layouts/mailer.text.haml +++ b/app/views/layouts/mailer.text.haml @@ -1 +1 @@ -= yield \ No newline at end of file += yield diff --git a/app/views/messages/index.html.haml b/app/views/messages/index.html.haml index af207dc8e..23adc0d8c 100644 --- a/app/views/messages/index.html.haml +++ b/app/views/messages/index.html.haml @@ -11,4 +11,4 @@ %small= m.updated_at.strftime("%b %e, %R %Z") = sanitize(Kramdown::Document.new(m.text).to_html) %hr - = paginate @messages, :theme => 'twitter-bootstrap' + = paginate @messages, :theme => 'twitter-bootstrap-4' diff --git a/app/views/teams/_admin_info_table.html.haml b/app/views/teams/_admin_info_table.html.haml index cc72fe989..c4ab3a7a1 100644 --- a/app/views/teams/_admin_info_table.html.haml +++ b/app/views/teams/_admin_info_table.html.haml @@ -1,22 +1,23 @@ %hr -%div.row - %div.span5 - %h3.muted= t('teams.summary.team_members_header') - %table.table.table-bordered.table-striped - %thead - %tr - %th= t('teams.show.admin_info_table.user_id') - %th= t('teams.show.admin_info_table.name') - %th= t('teams.show.admin_info_table.email') - %tbody - - @team.users.each do |user| +.container + .row + .col-sm + %h3.text-muted= t('teams.summary.team_members_header') + %table.table.table-bordered.table-striped.table-hover + %thead %tr - %td= link_to user.id, rails_admin.show_path('user', user) - %td= user.full_name - %td= user.email - %div.span7 - %h3.muted= t('teams.summary.per_user_statistics_header') - - if @team.solved_challenges.size == 0 - .zero-items-text= t('teams.summary.zero_items_text') - - else - = column_chart @per_user_stats, legend: 'bottom', xtitle: "User ID", stacked: true, colors: ['#b8d12f', '#00abca'] + %th= t('teams.show.admin_info_table.user_id') + %th= t('teams.show.admin_info_table.name') + %th= t('teams.show.admin_info_table.email') + %tbody + - @team.users.each do |user| + %tr + %td= link_to user.id, rails_admin.show_path('user', user) + %td= user.full_name + %td= user.email + .col-sm + %h3.text-muted= t('teams.summary.per_user_statistics_header') + - if @team.solved_challenges.size == 0 + .zero-items-text= t('teams.summary.zero_items_text') + - else + = column_chart @per_user_stats, legend: 'bottom', xtitle: "User ID", stacked: true, colors: ['#b8d12f', '#00abca'] diff --git a/app/views/teams/_challenge_list_tbody.html.haml b/app/views/teams/_challenge_list_tbody.html.haml index f4d228ac9..a225ac773 100644 --- a/app/views/teams/_challenge_list_tbody.html.haml +++ b/app/views/teams/_challenge_list_tbody.html.haml @@ -1,6 +1,7 @@ - tbody_class ||= '' +- tbody_id ||= '' -%tbody{class: tbody_class} +%tbody{class: tbody_class, id: tbody_id} - teams&.each&.with_index(starting_index) do |s, i| %tr %td= always_link_to_if_admin(s.challenge.open?, s.challenge.name, game_challenge_path(s.challenge)) diff --git a/app/views/teams/_defensive_points_table.html.haml b/app/views/teams/_defensive_points_table.html.haml index c9070c3ae..04308ae48 100644 --- a/app/views/teams/_defensive_points_table.html.haml +++ b/app/views/teams/_defensive_points_table.html.haml @@ -1,8 +1,8 @@ -%h3.muted= t('teams.summary.defensive_points_header') +%h3.text-muted= t('teams.summary.defensive_points_header') - if @defensive_points.size == 0 .zero-items-text= t('teams.summary.zero_items_text') - else - %table.table.table-bordered.table-striped + %table.table.table-bordered.table-striped.table-hover %thead %tr %th= t('teams.defensive_points_table.challenge_header') diff --git a/app/views/teams/_invites_form.html.haml b/app/views/teams/_invites_form.html.haml index b90b954f7..21814dd74 100644 --- a/app/views/teams/_invites_form.html.haml +++ b/app/views/teams/_invites_form.html.haml @@ -1,9 +1,7 @@ = form_for(@team, url: invite_team_path) do |team| %h4= t('teams.show.invite_member_header') = team.fields_for :user_invites, @team.user_invites.build do |invite_fields| - .control-group - = invite_fields.label :email, :class => "control-label" - .controls - = invite_fields.email_field :email, :class => "textarea" - .controls - = team.submit t('teams.show.invite_button'), :class => "btn" + .input-group.mb-2 + %input.form-control{:placeholder => "Email Address", :name => 'team[user_invites_attributes][0][email]', :type => "email"}/ + .input-group-append + = team.submit t('teams.show.invite_button'), :class => "btn btn-secondary" diff --git a/app/views/teams/_invites_table.html.haml b/app/views/teams/_invites_table.html.haml index 2c913bee1..0698fab32 100644 --- a/app/views/teams/_invites_table.html.haml +++ b/app/views/teams/_invites_table.html.haml @@ -1,4 +1,4 @@ -%table.table.table-condensed.table-striped.table-overflow +%table.table.table-condensed.table-striped.table-overflow.table-hover %thead %tr %th.span2= t('teams.invite.invites_table.email_header') @@ -15,16 +15,16 @@ %td - if current.user.nil? .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('teams.show.eligible_help') } - %i.icon-question-sign + = fa_icon 'question-circle' - else = eligible?(current) %td - if current.user.nil? .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('teams.show.eligible_help') } - %i.icon-question-sign + = fa_icon 'question-circle' - else = current.user.division - if @team_captain %td = link_to team_user_invite_path(@team, current), method: :delete, data: { confirm: t('teams.show.cancel_invite.confirm') } do - %i.icon-remove + = fa_icon 'ban' diff --git a/app/views/teams/_list.html.haml b/app/views/teams/_list.html.haml index a27aae40f..5c1d80509 100644 --- a/app/views/teams/_list.html.haml +++ b/app/views/teams/_list.html.haml @@ -5,13 +5,13 @@ = link_to( | t('users.join_team.reset_filters'), | reset_filterrific_url, | - :class => "btn btn-small" | + :class => "btn btn-small btn-secondary" | ) | = page_entries_info teams # provided by kaminari - if !teams.empty? %hr/ %div - %table.table.table-hover.table-bordered + %table.table.table-hover.table-bordered.table-hover %thead %tr %th= t('users.join_team.teams_table.name_header') @@ -27,5 +27,5 @@ %td= team.affiliation %td= team.slots_available %td= team.division.name - %td= button_to t('users.join_team.teams_table.request_join_button'), team_user_requests_path(team), :class => "btn btn-default" - = paginate teams, :theme => 'twitter-bootstrap' # provided by kaminari + %td= button_to t('users.join_team.teams_table.request_join_button'), team_user_requests_path(team), :class => "btn btn-primary" + = paginate teams, :theme => 'twitter-bootstrap-4' # provided by kaminari diff --git a/app/views/teams/_requests_table.html.haml b/app/views/teams/_requests_table.html.haml index a91153727..05308cac9 100644 --- a/app/views/teams/_requests_table.html.haml +++ b/app/views/teams/_requests_table.html.haml @@ -1,4 +1,4 @@ -%table.table.table-condensed.table-striped.table-overflow +%table.table.table-condensed.table-striped.table-overflow.table-hover %thead %tr %th.span2= t('teams.invite.invite_requests_table.email_header') @@ -18,6 +18,6 @@ - if @team_captain %td = link_to accept_team_user_request_path(@team,current) do - %i.icon-ok + =fa_icon 'check' = link_to team_user_request_path(@team, current), method: :delete, data: { confirm: t('teams.show.reject_request_confirm') } do - %i.icon-remove + =fa_icon 'remove' diff --git a/app/views/teams/_score_adjustments_table.html.haml b/app/views/teams/_score_adjustments_table.html.haml index 688808eee..16063ee94 100644 --- a/app/views/teams/_score_adjustments_table.html.haml +++ b/app/views/teams/_score_adjustments_table.html.haml @@ -1,4 +1,4 @@ -%table.table.table-bordered.table-striped +%table.table.table-bordered.table-striped.table-hover %thead %tr %th # diff --git a/app/views/teams/_solved_challenges_table.html.haml b/app/views/teams/_solved_challenges_table.html.haml index b69a6b2aa..f889c4a49 100644 --- a/app/views/teams/_solved_challenges_table.html.haml +++ b/app/views/teams/_solved_challenges_table.html.haml @@ -1,15 +1,16 @@ -%table.table.table-bordered.table-striped +%table.table.table-bordered.table-striped.table-hover %thead %tr %th= t('teams.summary.solved_challenges_table.challenge_header') %th= t('teams.summary.solved_challenges_table.points_header') %th= t('teams.summary.solved_challenges_table.when_header') - = render partial: 'teams/challenge_list_tbody', locals: { teams: @solved_challenges.slice(0..4), starting_index: 1 } + = render partial: 'teams/challenge_list_tbody', locals: { teams: @solved_challenges.slice(0..5), starting_index: 1 } / This part of the list is hidden until the user clicks the "Show/Hide" button below = render partial: 'teams/challenge_list_tbody', locals: { | - teams: @team.solved_challenges.slice(5..), | - starting_index: 6, | - tbody_class: 'hide' | + teams: @team.solved_challenges.slice(6..), | + starting_index: 7, | + tbody_id: 'hiddenUntilToggle', | + tbody_class: 'd-none' | } | - if @solved_challenges.size > 5 %tr{:id => "showBtnRow"} diff --git a/app/views/teams/_team_form.html.haml b/app/views/teams/_team_form.html.haml index ed0444a7c..0a10e64cc 100644 --- a/app/views/teams/_team_form.html.haml +++ b/app/views/teams/_team_form.html.haml @@ -1,17 +1,18 @@ -=form_for @team, :html => { :class => "form-horizontal"} do |f| - %legend= t('teams.edit.legend') - %label.label-custom= t('teams.edit.note') - .control-group - = f.label :team_name, :class => "control-label" +.col-md-6 + =form_for @team, :html => { :class => "form-horizontal"} do |f| + %legend= t('teams.edit.legend') + %label.label-custom= t('teams.edit.note') + .form-group + = f.label :team_name, :class => "control-label" + .controls + = f.text_field :team_name, :class => "form-control textarea", maxlength: 255 + .form-group + = f.label :affiliation, :class => "control-label" + .controls + = f.text_field :affiliation, :class => "form-control textarea", maxlength: 255 + .form-group + = f.label :division, :class => "control-label" + .controls + = f.collection_select :division_id, @divisions, :id, :name, {}, {:class => 'form-control'} .controls - = f.text_field :team_name, :class => "textarea", maxlength: 255 - .control-group - = f.label :affiliation, :class => "control-label" - .controls - = f.text_field :affiliation, :class => "textarea", maxlength: 255 - .control-group - = f.label :division, :class => "control-label" - .controls - = f.collection_select :division_id, @divisions, :id, :name - .controls - = button_tag "Submit", :class => "btn" + = button_tag "Submit", :class => "btn btn-primary" diff --git a/app/views/teams/_team_summary.html.haml b/app/views/teams/_team_summary.html.haml index 66332e6ed..e3df768a7 100644 --- a/app/views/teams/_team_summary.html.haml +++ b/app/views/teams/_team_summary.html.haml @@ -1,35 +1,40 @@ -%h3.muted= t('teams.summary.flag_submissions_header') -- if @team.solved_challenges.size > 0 - = line_chart @team_flag_submissions, library: {chart: {zoomType: 'x'}}, colors: ['#b8d12f', '#00abca'] - %p.muted - = t('game.zoom_help') -- else - .zero-items-text= t('teams.summary.zero_items_text') +.container + .row + .col-sm + %h3.text-muted= t('teams.summary.flag_submissions_header') + - if @team.solved_challenges.size > 0 + = line_chart @team_flag_submissions, library: {chart: {zoomType: 'x'}}, colors: ['#b8d12f', '#00abca'] + %p.text-muted + = t('game.zoom_help') + - else + .zero-items-text= t('teams.summary.zero_items_text') %hr -%div.row - %div.span5 - %h3.muted= t('teams.summary.solved_challenges_header') - - if @team.solved_challenges.size == 0 - .zero-items-text= t('teams.summary.zero_items_text') - - else - = render partial: 'teams/solved_challenges_table' - %div.span7 - %h3.muted= t('teams.summary.solved_challenges_chart_header') - - if @team.solved_challenges.size == 0 - .zero-items-text= t('teams.summary.zero_items_text') - - else - = pie_chart @flag_categories +.container + .row + .col-sm + %h3.text-muted= t('teams.summary.solved_challenges_header') + - if @team.solved_challenges.size == 0 + .zero-items-text= t('teams.summary.zero_items_text') + - else + = render partial: 'teams/solved_challenges_table' + .col-sm + %h3.text-muted= t('teams.summary.solved_challenges_chart_header') + - if @team.solved_challenges.size == 0 + .zero-items-text= t('teams.summary.zero_items_text') + - else + = pie_chart @flag_categories %hr -%div.row - %div.span5 +.container + .row - if @defensive_points - = render partial: 'teams/defensive_points_table' - %div.span7 - %h3.muted= t('teams.summary.score_adjustments_header') - - if @score_adjustments.size == 0 - .zero-items-text= t('teams.summary.zero_items_text') - - else - = render partial: 'teams/score_adjustments_table' + .col-sm + = render partial: 'teams/defensive_points_table' + .col-sm-6 + %h3.text-muted= t('teams.summary.score_adjustments_header') + - if @score_adjustments.size == 0 + .zero-items-text= t('teams.summary.zero_items_text') + - else + = render partial: 'teams/score_adjustments_table' - if current_user&.admin? = render partial: 'teams/admin_info_table' %br diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index 7979abd93..9bfec6d51 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -4,7 +4,7 @@ - content_for :subheading do = t('teams.show.subheading', affiliation: @team.affiliation) -%table.table.table-condensed.table-striped +%table.table.table-condensed.table-striped.table-hover#usertable %thead %tr %th.span1= t('teams.users_table.team_leader_header') @@ -14,13 +14,13 @@ %th= t('teams.users_table.remove_user_header') - if @team_captain %th - = t('teams.users_table.change_captian_header') + = t('teams.users_table.change_captain_header') - @team.users.each do |current| %tbody %tr{ :class=>'success' } %td -if current == @team.team_captain - %i.icon-ok + = fa_icon 'check' %td=current.email %td=current.division %td @@ -31,46 +31,52 @@ %td - if current_user.can_remove?(current) = link_to team_user_leave_team_path(current.team, current), method: :delete, data: { confirm: t('teams.show.remove_user_confirm') } do - %i.icon-remove + .pl-4 + = fa_icon 'user-times' - if @team_captain %td - if current_user.can_promote?(current) = link_to team_user_promote_path(current.team_id, current), method: :get, data: { confirm: t('teams.show.promote_confirm') } do - %i.icon-star + .pl-3.pl-lg-5 + = fa_icon 'exchange' %hr -.row - .span6 - %h4 - = t('teams.show.team_prize_eligibility_status') - = t('teams.show.eligible_currently') - - if @team.eligible? - = t('teams.show.eligible_true') - - else - %b= t('teams.show.eligible_false_not') - = t('teams.show.eligible_false') - .span6 - %h4 - = t('teams.show.team_division_status') - = t('teams.show.currently_selected_division', division: @team.division.name) - - if @team.appropriate_division_level? - = t('teams.show.division_true') - - else - = t('teams.show.division_false') +.container + .row + .col-sm + %h4= t('teams.show.team_prize_eligibility_status') + = t('teams.show.eligible_currently') + - if @team.eligible? + = t('teams.show.eligible_true') + - else + %b= t('teams.show.eligible_false_not') + = t('teams.show.eligible_false') + .col-sm + %h4= t('teams.show.team_division_status') + = t('teams.show.currently_selected_division', division: @team.division.name) + - if @team.appropriate_division_level? + = t('teams.show.division_true') + - else + = t('teams.show.division_false') %hr -.row - .span6 - %h3= t('teams.show.pending_invites_header') - - if @pending_invites.empty? - = t('teams.show.pending_invites_false') - - else - = render partial: 'teams/invites_table' - - if team_editable? - = render partial: 'teams/invites_form' - .span6 - %h3= t('teams.show.pending_requests_header') - - if @pending_requests.empty? - = t('teams.show.pending_requests_false') - - else - = render partial: 'teams/requests_table' +.container + .row + .col-sm + %h3= t('teams.show.pending_invites_header') + - if @pending_invites.empty? + = t('teams.show.pending_invites_false') + - else + = render partial: 'teams/invites_table' + .col-sm + %h3= t('teams.show.pending_requests_header') + - if @pending_requests.empty? + = t('teams.show.pending_requests_false') + - else + = render partial: 'teams/requests_table' +%br +.container + .row + .col-sm-6 + - if team_editable? + = render partial: 'teams/invites_form' %hr = render partial: 'team_summary' diff --git a/app/views/teams/summary.html.haml b/app/views/teams/summary.html.haml index 564535050..30f7c0f83 100644 --- a/app/views/teams/summary.html.haml +++ b/app/views/teams/summary.html.haml @@ -3,9 +3,10 @@ - content_for :subheading do = t('teams.show.subheading', affiliation: @team.affiliation) - -%h2.break-word= t('teams.summary.division_name', division: @team.division.name) -%h3.break-word= pluralize(@team.solved_challenges.size, t('teams.summary.solved_challenge')) +.container + .row + %h2.break-word= t('teams.summary.division_name', division: @team.division.name) + %h3.break-word= pluralize(@team.solved_challenges.size, t('teams.summary.solved_challenge')) %hr = render partial: 'team_summary' diff --git a/app/views/user_mailer/open_source.html.haml b/app/views/user_mailer/open_source.html.haml index cdef8cec1..e50670382 100644 --- a/app/views/user_mailer/open_source.html.haml +++ b/app/views/user_mailer/open_source.html.haml @@ -4,4 +4,4 @@ = t('user_mailer.open_source.view_solutions', title: @game.title) = link_to 'here', @game.open_source_url %p - = t('user_mailer.open_source.goodbye') \ No newline at end of file + = t('user_mailer.open_source.goodbye') diff --git a/app/views/users/_join_team_invites_table.html.haml b/app/views/users/_join_team_invites_table.html.haml index fb72dd5e6..5052dae79 100644 --- a/app/views/users/_join_team_invites_table.html.haml +++ b/app/views/users/_join_team_invites_table.html.haml @@ -1,7 +1,7 @@ %h3 = t('users.join_team.pending_team_invites_header') - %small= t('users.join_team.header_desc') -%table.table.table-condensed.table-striped + %small= t('users.join_team.invites_header_desc') +%table.table.table-condensed.table-striped.table-hover %thead %tr %th= t('teams.invite.incomming_invites_table.team_name_header') @@ -14,6 +14,6 @@ %td=current.created_at.strftime("%b %d %Y") %td = link_to accept_team_user_invite_path(current.team, current) do - %i.icon-ok + = fa_icon 'check' = link_to team_user_invite_path(current.team, current), method: :delete, data: {confirm: t('users.join_team.delete_invite_confirmation')} do - %i.icon-remove + = fa_icon 'remove' diff --git a/app/views/users/_join_team_requests_table.html.haml b/app/views/users/_join_team_requests_table.html.haml index a2a4d3ea0..d3c0af312 100644 --- a/app/views/users/_join_team_requests_table.html.haml +++ b/app/views/users/_join_team_requests_table.html.haml @@ -1,7 +1,7 @@ %h3 = t('users.join_team.pending_team_requests_header') %small= t('users.join_team.requests_header_desc') -%table.table.table-condensed.table-striped +%table.table.table-condensed.table-striped.table-hover %thead %tr %th= t('teams.invite.requested_join_team_table.team_name_header') @@ -14,4 +14,4 @@ %td=current.created_at.strftime("%b %d %Y") %td = link_to team_user_request_path(current.team, current), method: :delete, data: {confirm: t('users.join_team.delete_request_confirmation')} do - %i.icon-remove + = fa_icon 'remove' diff --git a/app/views/users/join_team.html.haml b/app/views/users/join_team.html.haml index 2f094663c..686c20e2c 100644 --- a/app/views/users/join_team.html.haml +++ b/app/views/users/join_team.html.haml @@ -5,42 +5,43 @@ - unless @pending_requests.empty? = render partial: 'users/join_team_requests_table' %h3= t('users.join_team.search_for_team_header') + = form_for_filterrific @filterrific, html: { class: 'form_for_filterrific' } do |f| - .well + .card.card-body.bg-light .container - .row - .span3 + .form-group.row + .col-md-3 Team Name - = f.text_field( | - :filter_team_name, | - class: 'filterrific-periodically-observed span3' | - ) | - .span3 + = f.text_field( | + :filter_team_name, | + class: 'filterrific-periodically-observed form-control span3' | + ) | + .col-md-3 Affiliation - = f.text_field( | - :filter_affiliation, | - class: 'filterrific-periodically-observed span3' | - ) | - .span2 + = f.text_field( | + :filter_affiliation, | + class: 'filterrific-periodically-observed form-control span3' | + ) | + .col-md-3 Location - = f.select( | - :location, | - @filterrific.select_options[:location], | - { :include_blank => '- Any -' }, | - :class => "span2", | - ) | - .span3 + = f.select( | + :location, | + @filterrific.select_options[:location], | + { :include_blank => '- Any -' }, | + :class => "span2 form-control", | + ) | + .col-md-3 Division - = f.select( | - :division, | - @filterrific.select_options[:division], | - { :include_blank => '- Any -' }, | - :class => "span3", | - ) | + = f.select( | + :division, | + @filterrific.select_options[:division], | + { :include_blank => '- Any -' }, | + :class => "span3 form-control", | + ) | .span1 = render_filterrific_spinner = render( | -partial: 'teams/list', | -locals: { teams: @teams } | + partial: 'teams/list', | + locals: { teams: @teams } | ) | diff --git a/app/views/users/passwords/edit.html.haml b/app/views/users/passwords/edit.html.haml index 7b17971ec..8c6b70ec9 100644 --- a/app/views/users/passwords/edit.html.haml +++ b/app/views/users/passwords/edit.html.haml @@ -2,7 +2,7 @@ = t('users.edit.password.password_edit_header') = form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| - if resource.errors.any? - .alert.alert-error + .alert.alert-danger %a.close{"data-dismiss" => "alert", :href => "#"} × = pluralize(resource.errors.count, "error") = t('users.edit.error') diff --git a/app/views/users/registrations/_delete_user_form.html.haml b/app/views/users/registrations/_delete_user_form.html.haml index b81b82bbb..b93919032 100644 --- a/app/views/users/registrations/_delete_user_form.html.haml +++ b/app/views/users/registrations/_delete_user_form.html.haml @@ -1,9 +1,8 @@ %hr -= form_for(resource, as: resource_name, url: registration_path(resource_name), :html => { :multipart => "true", :class => "form-horizontal"}, :method => :delete) do |f| - .control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.destroy') } - = f.label :area_of_study, t('users.edit.label.delete_account'), :class => "control-label" - .controls - .input-append - = f.password_field :current_password, :class => "textarea", :placeholder => t('users.edit.label.current_password_placeholder') - = button_tag t('users.edit.label.delete_account'), :label => t('users.edit.label.delete_account'), :class => 'btn btn-danger', :data => { :confirm => t('users.destroy.confirm') } += form_for(resource, as: resource_name, url: registration_path(resource_name), :html => { :multipart => "true", :class => "form-horizontal", :id => 'delete-user-form' }, :method => :delete) do |f| + .form-group + = f.label :delete_account + .input-group + = f.password_field :current_password, :class => "form-control textarea", :placeholder => t('users.edit.label.current_password_placeholder') + .input-group-append + = button_tag t('users.edit.label.delete_account'), :label => t('users.edit.label.delete_account'), :class => 'btn btn-danger', :data => { :confirm => t('users.destroy.confirm') } diff --git a/app/views/users/registrations/_update_user_form.html.haml b/app/views/users/registrations/_update_user_form.html.haml index be48ae09f..78076dca1 100644 --- a/app/views/users/registrations/_update_user_form.html.haml +++ b/app/views/users/registrations/_update_user_form.html.haml @@ -1,15 +1,13 @@ -.control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.resume') } - = f.label :resume, :class => "control-label" - .controls - = f.file_field :resume -.control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.transcript') } - = f.label :unofficial_transcript, :class => "control-label" - .controls - = f.file_field :transcript -.control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.password') } - = f.label :current_password, :class => "control-label-required" - .controls - = f.password_field :current_password, :class => "textarea" +%hr.my-3 +.form-group + = f.label :resume, :class => "control-label" + = f.file_field :resume, :class => "col-sm-12" +.form-group + = f.label :unofficial_transcript, :class => "control-label" + = f.file_field :transcript, :class => "col-sm-12" +%hr.my-3 +.form-group + = f.label :current_password, :class => "form-control-file control-label-required" + = f.password_field :current_password, :class => "form-control textarea" + %small.form-text.text-muted + = t('users.edit.help.password') diff --git a/app/views/users/registrations/_user_form.html.haml b/app/views/users/registrations/_user_form.html.haml index f028f77f2..8299450bf 100644 --- a/app/views/users/registrations/_user_form.html.haml +++ b/app/views/users/registrations/_user_form.html.haml @@ -1,70 +1,67 @@ -= form_for(resource, as: resource_name, url: registration_path(resource_name), :html => { :multipart => "true", :class => "form-horizontal"}) do |f| - - if resource.errors.any? - .alert.alert-error - %a.close{"data-dismiss" => "alert", :href => "#"} × - = pluralize(resource.errors.count, "error") - = t('users.edit.error') - %ul.errors - - resource.errors.full_messages.each do |msg| - %li= msg - %label.label-custom - = t('users.new.required_fields_notice_1') - %span{:style => "color: red;"} * - = t('users.new.required_fields_notice_2') - .control-group - = f.label :full_name, :class => "control-label-required" - .controls - = f.text_field :full_name, :class => "textarea", maxlength: 255 - .control-group - = f.label :email, :class => "control-label-required" - .controls - = f.email_field :email, :class => "textarea", :value => params[:email] ||= f.object.email - .control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.affiliation') } +.col-md-6 + = form_for(resource, as: resource_name, url: registration_path(resource_name), :html => { :multipart => "true", :class => "form-horizontal", id: 'user-form'}) do |f| + - if resource.errors.any? + .alert.alert-danger + %a.close{"data-dismiss" => "alert", :href => "#"} × + = pluralize(resource.errors.count, "error") + = t('users.edit.error') + %ul.errors + - resource.errors.full_messages.each do |msg| + %li= msg + %label.label-custom + = t('users.new.required_fields_notice_1') + %span{:style => "color: red;"} * + = t('users.new.required_fields_notice_2') + .form-group + = f.label :full_name, :class => "control-label-required" + = f.text_field :full_name, :class => "form-control textarea", maxlength: 255 + .form-group + = f.label :email, :class => "control-label-required" + = f.email_field :email, :class => "form-control textarea", :value => params[:email] ||= f.object.email + .form-group = f.label :affiliation, :class => "control-label-required" - .controls - = f.text_field :affiliation, :class => "textarea" - .control-group - = f.label :year_in_school, :class => "control-label-required" - .controls - = f.select :year_in_school, options_for_select(year_in_school_enum, resource.year_in_school), { :include_blank => '' }, :onChange => "hidePrizesCheckbox()" - .control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.state') } + = f.text_field :affiliation, :class => "form-control textarea", maxlength: 255 + %small.form-text.text-muted + = t('users.edit.help.affiliation') + .form-group + = f.label :year_in_school, :class => "control-label-required" + = f.select :year_in_school, options_for_select(year_in_school_enum, resource.year_in_school), { :include_blank => '' }, :class => "form-control", :onChange => "hidePrizesCheckbox()" + %small.form-text.text-muted + = t('users.edit.help.year_in_school') + .form-group = f.label :state, :class => "control-label-required" - .controls - = f.select :state, options_for_select(state_enum, resource.state), { :include_blank => '' }, :onChange => "hidePrizesCheckbox()" - .control-group - = f.label :password, :class => required_for_update?(on_update_page) - .controls - = f.password_field :password, :input_html => {:autofocus => true}, :class => "textarea" - .control-group - = f.label :password_confirmation, t('users.edit.label.password_confirmation_2'), :class => required_for_update?(on_update_page) - .controls - = f.password_field :password_confirmation, :class => "textarea" - .control-group#compete-for-prizes - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.compete_for_prizes') } - = f.label :compete_for_prizes, :class => "control-label" - .controls - = f.check_box :compete_for_prizes - .control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.interested_in_employment', organization: @game.organization) } - = f.label :interested_in_employment, :class => "control-label" - .controls - = f.check_box :interested_in_employment - .control-group - .helpertext-wrapper{ 'data-toggle' => 'tooltip', 'data-placement' => 'right', :title => t('users.edit.help.age') } + = f.select :state, options_for_select(state_enum, resource.state), { :include_blank => '' }, :class => "form-control", :onChange => "hidePrizesCheckbox()" + %small.form-text.text-muted + = t('users.edit.help.state') + .form-group + = f.label :password, :class => required_for_update?(on_update_page) + = f.password_field :password, :input_html => {:autofocus => true}, :class => "form-control textarea" + .form-group + = f.label :password_confirmation, t('users.edit.label.password_confirmation_2'), :class => required_for_update?(on_update_page) + = f.password_field :password_confirmation, :class => "form-control textarea" + .form-group = f.label :age, :class => "control-label" - .controls - = f.text_field :age, :class => "textarea" - .control-group - = f.label :area_of_study, t('users.edit.label.major_area_of_study'), :class => "control-label" + = f.number_field :age, :class => "form-control textarea" + .form-group + = f.label :area_of_study, t('users.edit.label.major_area_of_study'), :class => "control-label" + = f.text_field :area_of_study, :class => "form-control textarea" + %hr.my-3 + .form-check.form-group#compete-for-prizes + = f.check_box :compete_for_prizes, :class => "form-check-input" + = f.label :compete_for_prizes, :class => "form-check-label" + %small.form-text.text-muted + = t('users.edit.help.compete_for_prizes') + .form-check.form-group + = f.check_box :interested_in_employment, :class => "form-check-input" + = f.label :interested_in_employment, :class => "form-check-label" + %small.form-text.text-muted + = t('users.edit.help.interested_in_employment', organization: @game.organization || t('default_organization')) + .mb-3 + -# If a user is updating their information then on_update_page should be passed to the partial as true, + -# if this is a new user registering then on_update_page should be false. + - if on_update_page + = render partial: 'users/registrations/update_user_form', locals: { f: f } .controls - = f.text_field :area_of_study, :class => "textarea" - -# If a user is updating their information then on_update_page should be passed to the partial as true, - -# if this is a new user registering then on_update_page should be false. + = invisible_recaptcha_tags text: 'Submit', callback: 'submitUserForm', :class => "btn btn-primary" - if on_update_page - = render partial: 'users/registrations/update_user_form', locals: { f: f } - .controls - = invisible_recaptcha_tags text: 'Submit', :class => "btn" -- if on_update_page - = render partial: 'users/registrations/delete_user_form' + = render partial: 'users/registrations/delete_user_form' diff --git a/app/views/users/sessions/new.html.haml b/app/views/users/sessions/new.html.haml index da7aa7131..63f5c73a7 100644 --- a/app/views/users/sessions/new.html.haml +++ b/app/views/users/sessions/new.html.haml @@ -2,24 +2,21 @@ = t('users.login.login_header') %legend= t('users.new.sessions_legend') = form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "form-horizontal"}) do |f| - .control-group + .form-group = f.label :email, :class => "control-label" - .controls - = f.email_field :email, :tabindex => "1" - = render 'users/shared/create_user_link' - .control-group + = f.email_field :email, :tabindex => "1", :class => "form-control w-50" + = render 'users/shared/create_user_link' + .form-group = f.label :password, :class => "control-label" - .controls - = f.password_field :password, :tabindex => "2" - = render 'users/shared/reset_your_password' + = f.password_field :password, :tabindex => "2", :class => "form-control w-50" + = render 'users/shared/reset_your_password' - if devise_mapping.rememberable? - .control-group - .controls - = f.label :remember_me, :class => "checkbox" do - = f.check_box :remember_me, :class => "checkbox" - = t('users.login.remember_login') - .controls - = button_tag "Submit", :class => "btn", :tabindex => "3" + .form-group + .form-check + = f.check_box :remember_me, :class => "form-check-input" + %label.form-check-label= t('users.login.remember_login') + .form-group + = button_tag "Submit", :class => "btn btn-primary", :tabindex => "3" %br/ .controls = render 'users/shared/resend_confirmation_email' diff --git a/app/views/users/shared/_create_user_link.html.haml b/app/views/users/shared/_create_user_link.html.haml index 697844ef8..8100ad584 100644 --- a/app/views/users/shared/_create_user_link.html.haml +++ b/app/views/users/shared/_create_user_link.html.haml @@ -1,2 +1,2 @@ - if devise_mapping.registerable? && controller_name != 'registrations' - = link_to t('devise.registrations.new_user'), new_user_registration_path, :class => "space-text-from-input" + = link_to t('devise.registrations.new_user'), new_user_registration_path, :class => "btnspace-text-from-input" diff --git a/app/views/users/shared/_reset_your_password.html.haml b/app/views/users/shared/_reset_your_password.html.haml index 922c0484b..9a2eb2832 100644 --- a/app/views/users/shared/_reset_your_password.html.haml +++ b/app/views/users/shared/_reset_your_password.html.haml @@ -1,2 +1,2 @@ - if devise_mapping.recoverable? && controller_name != 'passwords' - = link_to t('devise.passwords.reset'), new_password_path(resource_name), :class => "space-text-from-input" + = link_to t('devise.passwords.reset'), new_password_path(resource_name) diff --git a/app/views/users/shared/_retrieve_access.html.haml b/app/views/users/shared/_retrieve_access.html.haml index 8a5c035bc..cc42011df 100644 --- a/app/views/users/shared/_retrieve_access.html.haml +++ b/app/views/users/shared/_retrieve_access.html.haml @@ -1,14 +1,16 @@ - if resource.errors.any? - .alert.alert-error + .alert.alert-danger %a.close{"data-dismiss" => "alert", :href => "#"} × = pluralize(resource.errors.count, "error") = t('users.edit.error') %ul.errors - resource.errors.full_messages.each do |msg| %li= msg -= user.label :email, :class => "control-label-required" -.input-append - = user.email_field :email, :id => "appendedInputButton" - = user.submit t('users.edit.password.retrieve_access_instructions'), :class => "btn" -%br/ -= render "users/shared/links" +.form-group + = user.label :email, :class => "control-label-required" + .input-group + = user.email_field :email, :class => "form-control textarea" + .input-group-append + = user.submit t('users.edit.password.retrieve_access_instructions'), :class => "btn btn-primary" + %br/ + = render "users/shared/links" diff --git a/config/initializers/application_module.rb b/config/initializers/application_module.rb index 1629c4a85..7ef34a7c7 100644 --- a/config/initializers/application_module.rb +++ b/config/initializers/application_module.rb @@ -1 +1 @@ -require 'application_module.rb' \ No newline at end of file +require 'application_module.rb' diff --git a/config/initializers/customize_error.rb b/config/initializers/customize_error.rb new file mode 100644 index 000000000..08a855ba3 --- /dev/null +++ b/config/initializers/customize_error.rb @@ -0,0 +1,11 @@ +# https://jasoncharnes.com/bootstrap-4-rails-fields-with-errors/ + +ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| + class_attr_index = html_tag.index 'class="' + + if class_attr_index + html_tag.insert class_attr_index+7, 'is-invalid ' + else + html_tag.insert html_tag.index('>'), ' class="is-invalid"' + end +end diff --git a/config/initializers/obscenity_module.rb b/config/initializers/obscenity_module.rb index bb524aac2..3cd6162a5 100644 --- a/config/initializers/obscenity_module.rb +++ b/config/initializers/obscenity_module.rb @@ -1 +1 @@ -require 'obscenity/active_model' \ No newline at end of file +require 'obscenity/active_model' diff --git a/config/initializers/paper_trail.rb b/config/initializers/paper_trail.rb index 30d87fe54..4af1ebabc 100644 --- a/config/initializers/paper_trail.rb +++ b/config/initializers/paper_trail.rb @@ -1 +1 @@ -PaperTrail.config.track_associations = true \ No newline at end of file +PaperTrail.config.track_associations = true diff --git a/config/initializers/rails_admin.rb b/config/initializers/rails_admin.rb index dd19f20c0..c68b3e37e 100644 --- a/config/initializers/rails_admin.rb +++ b/config/initializers/rails_admin.rb @@ -375,6 +375,7 @@ field :start field :stop field :description + field :registration_enabled field :board_layout field :team_size field :organization diff --git a/config/initializers/user_module.rb b/config/initializers/user_module.rb index 9d8064a7c..2180f345a 100644 --- a/config/initializers/user_module.rb +++ b/config/initializers/user_module.rb @@ -1 +1 @@ -require 'user_module.rb' \ No newline at end of file +require 'user_module.rb' diff --git a/config/locales/en.yml b/config/locales/en.yml index 46c3ed470..85d6c7842 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -55,7 +55,7 @@ en: division_header: Appropriate Division prize_eligibility_header: Prize Eligible remove_user_header: Remove - change_captian_header: Change Captain + change_captain_header: Change Captain compete_for_prizes_true: 'Yes' compete_for_prizes_false: 'No' summary: @@ -260,6 +260,7 @@ en: current_password_placeholder: Current Password delete_account: Delete Account major_area_of_study: Major/Area of study + submit: 'Submit' help: affiliation: >- If you are a student, please list your school. If you are an industry @@ -434,3 +435,5 @@ en: sign in attempts. unlock_line_2: 'Click the link below to unlock your account:' unlock_account_link: Unlock my account + # Set a default fallback for use if no organization is set on the game. + default_organization: 'us' diff --git a/test/integration/achievement_display_modes_test.rb b/test/integration/achievement_display_modes_test.rb index 2558cc861..f0e97b8dd 100644 --- a/test/integration/achievement_display_modes_test.rb +++ b/test/integration/achievement_display_modes_test.rb @@ -26,7 +26,7 @@ def setup sign_in create(:user) get "/game/achievements" - assert_select 'table[class=table\ table-bordered\ table-striped]' do + assert_select 'table[class=table\ table-bordered\ table-striped\ table-hover]' do assert_select 'thead' do assert_select 'tr' do assert_select 'th:nth-child(1)', I18n.t('achievements.index.table_header_achievement_name') diff --git a/test/integration/application_display_modes_test.rb b/test/integration/application_display_modes_test.rb index 44ddbfdb2..00876be88 100644 --- a/test/integration/application_display_modes_test.rb +++ b/test/integration/application_display_modes_test.rb @@ -26,14 +26,14 @@ def setup test 'navigation bar shows all fields when logged out' do get "/" - assert_select 'a[class=brand]', @game.organization, "Organization should show in navigation bar" + assert_select 'a[class=navbar-brand]', @game.organization, "Organization should show in navigation bar" assert_select "a[href=#{game_path.dump}]", I18n.t('application.navbar.challenges'), "Challenges should show in navigation bar" assert_select "a[href=#{game_messages_path.dump}]", I18n.t('application.navbar.messages'), "Messages should show in navigation bar" assert_select "a[href=#{game_achievements_path.dump}]", I18n.t('application.navbar.achievements'), "Achievements should show in navigation bar" assert_select "a[href=#{game_summary_path.dump}]", I18n.t('application.navbar.summary'), "Summary should show in navigation bar" assert_select "a[href=#{@game.contact_url.dump}]", I18n.t('application.navbar.contact'), "Contact should show in navigation bar if contact_url is defined in game" - assert_select 'a[class=dropdown-toggle]', I18n.t('home.index.login_or_register'), "Log in / Register should show in navigation bar while not signed in" + assert_select 'a[class=nav-link\ dropdown-toggle]', I18n.t('home.index.login_or_register'), "Log in / Register should show in navigation bar while not signed in" assert_select "a[href=#{new_user_session_path.dump}]", I18n.t('home.index.login'), "Login should show in navigation bar dropdown while not signed in" assert_select "a[href=#{new_user_registration_path.dump}]", I18n.t('home.index.register'), "Register should show in navigation bar dropdown while not signed in" end diff --git a/test/integration/summary_display_modes_test.rb b/test/integration/summary_display_modes_test.rb index 1d0d55f1e..c4691dd16 100644 --- a/test/integration/summary_display_modes_test.rb +++ b/test/integration/summary_display_modes_test.rb @@ -8,9 +8,8 @@ def setup @game = create(:active_game) end - test 'summary header shows on summary page' do + test 'No teams show header shows on summary page when there are no teams' do get "/game/summary" - Team.destroy_all assert_select 'h1', /Game Summary/, 'Game summary header should show on the game summary page' assert_select 'h4', /No Teams/, 'No teams should show when there are no teams on the game summary page' @@ -20,8 +19,8 @@ def setup team = create(:team) sign_in create(:user) get "/game/summary" - puts team.achievements - assert_select 'table[class=table\ table-bordered\ table-striped]' do + puts team.achievements + assert_select 'table[class=table\ table-bordered\ table-striped\ table-hover]' do assert_select 'thead' do assert_select 'tr' do assert_select 'th:nth-child(1)', '#' diff --git a/test/integration/team_display_modes_test.rb b/test/integration/team_display_modes_test.rb index 53cc94b95..3954ec81c 100644 --- a/test/integration/team_display_modes_test.rb +++ b/test/integration/team_display_modes_test.rb @@ -7,8 +7,15 @@ class TeamDisplayModesTest < ActionDispatch::IntegrationTest def setup @game = create(:active_game) end - - test 'team creation page' do + + test 'team creation header shows when visiting team creation page' do + sign_in create(:user) + get "/teams/new" + + assert_select 'h1', /Create a Team/ + end + + test 'ensure that there is a form on the team creation page' do sign_in create(:user) get "/teams/new" @@ -31,7 +38,7 @@ def setup get "/users/join_team" assert_select 'form[id=filterrific_filter]' do - assert_select 'div[class=row]' do + assert_select 'div[class=form-group\ row]' do assert_select 'div:nth-child(1)', /Team Name/ assert_select 'div:nth-child(2)', /Affiliation/ assert_select 'div:nth-child(3)', /Location/ @@ -54,7 +61,7 @@ def setup assert_select 'h1', /ineligible/ assert_select 'h1', /100/ - assert_select 'table[class=table\ table-condensed\ table-striped]' do + assert_select 'table[class=table\ table-condensed\ table-striped\ table-hover]' do assert_select 'thead' do assert_select 'tr' do assert_select 'th:nth-child(1)', I18n.t('teams.users_table.team_leader_header') @@ -62,7 +69,7 @@ def setup assert_select 'th:nth-child(3)', I18n.t('teams.users_table.grade_header') assert_select 'th:nth-child(4)', I18n.t('teams.users_table.prize_eligibility_header') assert_select 'th:nth-child(5)', I18n.t('teams.users_table.remove_user_header') - assert_select 'th:nth-child(6)', I18n.t('teams.users_table.change_captian_header') + assert_select 'th:nth-child(6)', I18n.t('teams.users_table.change_captain_header') end end assert_select 'tbody' do @@ -105,7 +112,7 @@ def setup get "/teams/#{team.id}/summary" - assert_select 'table[class=table\ table-bordered\ table-striped]' do + assert_select 'table[class=table\ table-bordered\ table-striped\ table-hover]' do assert_select 'thead' do assert_select 'tr' do assert_select 'th:nth-child(1)', I18n.t('teams.summary.solved_challenges_table.challenge_header') diff --git a/test/integration/user_display_modes_test.rb b/test/integration/user_display_modes_test.rb index 8a1ab78ec..1c0145b33 100644 --- a/test/integration/user_display_modes_test.rb +++ b/test/integration/user_display_modes_test.rb @@ -15,11 +15,11 @@ def setup assert_select 'h1', /Edit Account/ end - test 'ensure that there is a form on the team creation page' do + test 'ensure that there is a edit and delete form on the user edit page' do sign_in create(:user) get "/users/edit" - assert_select 'form[id=edit_user]' do + assert_select 'form[id=user-form]' do assert_select 'label', 'Full name' assert_select 'label', 'Email' assert_select 'label', 'Affiliation' @@ -35,5 +35,9 @@ def setup assert_select 'label', 'Unofficial transcript' assert_select 'label', 'Current password' end + + assert_select 'form[id=delete-user-form]' do + assert_select 'label', 'Delete account' + end end end