diff --git a/.gitignore b/.gitignore index b83dbe65..410f6a29 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,6 @@ tags .env .env*.local !.env.development + +# Ignore local TODO files +TODO.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f2caf9e5..f38981e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.3.0] - 2026-01 + +### Added + +- Enabled Sass source maps for front-end debugging in development +- Added Autoprefixer initialiser for Bootstrap gem compatibility +- Added Popper.js dependency for Bootstrap functionality +- Added `update` Makefile target to check outdated dependencies +- Added cookie banner styling using Bootstrap conventions + +### Changed + +- Replaced `bootstrap-sass` with `bootstrap` gem for Dart Sass compatibility + [#309](https://github.com/epimorphics/ppd-explorer/issues/309) +- Modernised stylesheets after Sass migration +- Improved asset compression for smaller bundles +- Updated modals and forms to Bootstrap 5 notation +- Enhanced error page layout and status messages +- Converted form groups to semantic fieldsets for accessibility +- Replaced deprecated `lighten` with `color.adjust` Sass module +- Improved page layout padding and form spacing +- Enhanced action buttons responsiveness +- Streamlined Makefile with inline help +- Cleaned up startup log output + +### Removed + +- Removed `sass-rails` gem and deprecated dependencies +- Removed duplicated search form partial + ## [2.2.3] - 2025-11 ### Changed diff --git a/Gemfile b/Gemfile index dc2fabac..211d6bb3 100644 --- a/Gemfile +++ b/Gemfile @@ -8,15 +8,18 @@ gem 'rails' # Use Puma as the app server gem 'puma' -# See https://github.com/sstephenson/execjs#readme for more supported runtimes +# See https://github.com/rails/execjs#readme for more supported runtimes gem 'execjs' # gem 'therubyracer', platforms: :ruby gem 'libv8-node' +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder' gem 'jquery-rails' -gem 'bootstrap-sass' +gem 'autoprefixer-rails' +gem 'dartsass-sprockets', '~> 3.2' + gem 'haml-rails' gem 'rubocop' @@ -39,18 +42,6 @@ gem 'yajl-ruby', require: 'yajl' gem 'stackprof' gem 'sentry-rails' # rubocop:disable Bundler/OrderedGems -# Assets group is temporarily disabled due to versioning issues with Rails -# group :assets do -# Use SCSS for stylesheets -gem 'sass-rails' -# ! Webpacker removes the need for Uglifier so we can safely remove it. -# ! If you want to use Uglifier, uncomment the line below -# ! and ensure you have the 'uglifier' gem in your Gemfile. -# ! See https://www.mintbit.com/blog/rails-5-6-upgrade-es6-uglifier-bug/ -# Use Uglifier as compressor for JavaScript assets -# gem 'uglifier', require: false -# end - group :doc do gem 'sdoc', require: false end @@ -84,6 +75,12 @@ group :development do gem 'flamegraph' gem 'memory_profiler' + + # TODO: While running the rails app locally for testing you can set gems to your local path + # ! These 'local' paths do not work with a docker image - use the repo instead + # gem 'data_services_api', path: '~/Epimorphics/shared/data_services_api' + # gem 'json_rails_logger', path: '~/Epimorphics/shared/json-rails-logger' + # gem 'lr_common_styles', path: '~/Epimorphics/clients/land-registry/projects/lr_common_styles' end # TODO: In production you want to set this to the gem from the epimorphics package repo @@ -92,9 +89,3 @@ source 'https://rubygems.pkg.github.com/epimorphics' do gem 'json_rails_logger' gem 'lr_common_styles' end - -# TODO: While running the rails app locally for testing you can set gems to your local path -# ! These 'local' paths do not work with a docker image - use the repo instead -# gem 'data_services_api', path: '~/Epimorphics/shared/data_services_api' -# gem 'json_rails_logger', path: '~/Epimorphics/shared/json-rails-logger' -# gem 'lr_common_styles', path: '~/Epimorphics/clients/land-registry/projects/lr_common_styles' diff --git a/Gemfile.lock b/Gemfile.lock index 1307fe82..2670ebd8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -94,9 +94,8 @@ GEM base64 (0.3.0) benchmark (0.5.0) bigdecimal (3.3.1) - bootstrap-sass (3.4.1) - autoprefixer-rails (>= 5.2.1) - sassc (>= 2.0.0) + bootstrap (5.3.5) + popper_js (>= 2.11.8, < 3) builder (3.3.0) byebug (12.0.0) capybara (3.40.0) @@ -115,6 +114,12 @@ GEM rexml crass (1.0.6) csv (3.3.5) + dartsass-sprockets (3.2.1) + railties (>= 4.0.0) + sassc-embedded (~> 1.80.1) + sprockets (> 3.0) + sprockets-rails + tilt date (3.5.0) diff-lcs (1.6.2) docile (1.4.1) @@ -151,6 +156,27 @@ GEM ffi (~> 1.0) globalid (1.3.0) activesupport (>= 6.1) + google-protobuf (4.33.2) + bigdecimal + rake (>= 13) + google-protobuf (4.33.2-aarch64-linux-gnu) + bigdecimal + rake (>= 13) + google-protobuf (4.33.2-aarch64-linux-musl) + bigdecimal + rake (>= 13) + google-protobuf (4.33.2-arm64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.33.2-x86_64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.33.2-x86_64-linux-gnu) + bigdecimal + rake (>= 13) + google-protobuf (4.33.2-x86_64-linux-musl) + bigdecimal + rake (>= 13) govuk_elements_rails (3.0.2) govuk_frontend_toolkit (>= 5.2.0) rails (>= 4.1.0) @@ -273,6 +299,7 @@ GEM parser (3.3.10.0) ast (~> 2.4.1) racc + popper_js (2.11.8) pp (0.6.3) prettyprint prettyprint (0.2.0) @@ -378,19 +405,27 @@ GEM rubyzip (3.2.2) sass (3.7.4) sass-listen (~> 4.0.0) + sass-embedded (1.97.1-aarch64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-aarch64-linux-musl) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-arm-linux-gnueabihf) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-arm-linux-musleabihf) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-x86_64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-x86_64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.97.1-x86_64-linux-musl) + google-protobuf (~> 4.31) 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) - ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt + sassc-embedded (1.80.8) + sass-embedded (~> 1.80) sdoc (2.6.5) rdoc (>= 5.0) securerandom (0.4.1) @@ -490,8 +525,8 @@ GEM json lograge railties - lr_common_styles (2.3.1) - bootstrap-sass (~> 3.4.1) + lr_common_styles (3.0.0) + bootstrap (~> 5.3.2) font-awesome-rails (~> 4.7.0) govuk_elements_rails (= 3.0.2) govuk_frontend_toolkit (~> 9.0) @@ -502,7 +537,6 @@ GEM modernizr-rails (~> 2.7) modulejs-rails (~> 2.2.0) rails (~> 8.0) - sass-rails (~> 6.0) PLATFORMS aarch64-linux @@ -517,10 +551,11 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - bootstrap-sass + autoprefixer-rails byebug capybara csv + dartsass-sprockets (~> 3.2) data_services_api! dotenv execjs @@ -555,7 +590,6 @@ DEPENDENCIES rubocop rubocop-rails ruby-lsp - sass-rails sdoc selenium-webdriver sentry-rails diff --git a/Makefile b/Makefile index dae13581..ff11d6b6 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,16 @@ -.PHONY: assets auth check clean image lint publish realclean run tag test vars +.PHONY: assets auth check clean image lint publish realclean run tag test update vars -ACCOUNT?=$(shell aws sts get-caller-identity | jq -r .Account) ALPINE_VERSION?=3.22 -AWS_REGION?=eu-west-1 BUNDLER_VERSION?=$(shell tail -1 Gemfile.lock | tr -d ' ') +RUBY_VERSION?=$(shell cat .ruby-version) +ACCOUNT?=$(shell aws sts get-caller-identity | jq -r .Account) +AWS_REGION?=eu-west-1 ECR?=${ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com GPR_OWNER?=epimorphics NAME?=$(shell awk -F: '$$1=="name" {print $$2}' deployment.yaml | sed -e 's/[[:blank:]]//g') PAT?=$(shell read -p 'Github access token:' TOKEN; echo $$TOKEN) PORT?=3001 -RUBY_VERSION?=$(shell cat .ruby-version) + SHORTNAME?=$(shell echo ${NAME} | cut -f2 -d/) STAGE?=dev API_SERVICE_URL?=http://localhost:8888 @@ -24,9 +25,9 @@ TAG?=$(shell printf '%s_%s_%08d' ${VERSION} ${COMMIT} ${GITHUB_RUN_NUMBER}) IMAGE?=${NAME}/${STAGE} REPO?=${ECR}/${IMAGE} -GITHUB_TOKEN=.github-token BUNDLE_CFG=.bundle/config BUNDLE=./bin/bundle +GITHUB_TOKEN=.github-token RAILS=./bin/rails ${BUNDLE_CFG}: ${GITHUB_TOKEN} @@ -35,20 +36,25 @@ ${BUNDLE_CFG}: ${GITHUB_TOKEN} ${GITHUB_TOKEN}: @echo ${PAT} > ${GITHUB_TOKEN} -all: image +all: image ## Default target: build the Docker image + +assets: bundles compiled ## Compile assets for serving + @echo assets completed. + +auth: ${GITHUB_TOKEN} ${BUNDLE_CFG} ## Set up authentication for GitHub and Bundler + @echo "Authentication set up for GitHub and Bundler." -assets: - @echo "Installing bundled gems ..." +bundles: ## Install Ruby gems via Bundler + @echo "Installing Ruby gems via Bundler..." @${BUNDLE} install - @echo "Cleaning and precompiling static assets ..." - @${BUNDLE} exec rake assets:clean assets:precompile -auth: ${GITHUB_TOKEN} ${BUNDLE_CFG} +check: checks ## Alias for `checks` target + @echo "All checks passed." -check: lint test +checks: lint test ## Run all checks: linting and tests @echo "All checks passed." -clean: +clean: ## Clean up temporary and compiled files @echo "Cleaning up ${SHORTNAME} files..." # Clean up the project @[ -d public/assets ] && ${RAILS} assets:clobber || : @@ -57,7 +63,21 @@ clean: # Remove temporary files and directories @@ rm -rf bundle coverage log node_modules tmp -image: auth +compiled: ## Compile assets for production + @echo "Cleaning and precompiling static assets ..." + @${RAILS} assets:clobber assets:precompile + +forceclean: realclean ## Remove all bundled files + @${BUNDLE} clean --force || : + +help: ## Display this message + @echo "Available make targets:" + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "%-20s %s\n", $$1, $$2}' + @echo "" + @echo "Environment variables (optional: all variables have defaults):" + @make vars + +image: auth ## Build the Docker image @echo Building ${REPO}:${TAG} ... @docker build \ --build-arg ALPINE_VERSION=${ALPINE_VERSION} \ @@ -73,48 +93,59 @@ image: auth . @echo Done. -forceclean: realclean -# Remove all bundled files - @${BUNDLE} clean --force || : - -lint: assets - @${BUNDLE} exec rubocop +lint: rubocop ## Run linting checks + @echo "All linting complete." -name: +name: ## Display the shortname of the application @echo ${SHORTNAME} -publish: image +publish: image ## Publish the Docker image to the registry @echo Publishing image: ${REPO}:${TAG} ... @docker tag ${NAME}:${TAG} ${REPO}:${TAG} 2>&1 @docker push ${REPO}:${TAG} 2>&1 @echo Done. -realclean: clean +realclean: clean ## Remove all generated files and authentication @echo "Removing authentication from ${SHORTNAME}..." @rm -f ${GITHUB_TOKEN} ${BUNDLE_CFG} -run: start +rubocop: ## Run RuboCop linting + @echo "Running RuboCop linting for ${SHORTNAME} ..." +# Auto-correct offenses safely where possible with the `-a` flag + @${BUNDLE} exec rubocop -a + +run: start ## Run the Docker container locally @if docker network inspect dnet > /dev/null 2>&1; then echo "Using docker network dnet"; else echo "Create docker network dnet"; docker network create dnet; sleep 2; fi @docker run ${RUN_VARS} ${PORT}:3000 --env API_SERVICE_URL=${API_SERVICE_URL} --network dnet --rm --name ${SHORTNAME} ${REPO}:${TAG} -server: start +server: start ## Run the Rails server locally @API_SERVICE_URL=${API_SERVICE_URL} ${RAILS} server -p ${PORT} -start: stop +start: stop ## Start the application @echo "Starting ${SHORTNAME} pointing to ${API_SERVICE_URL} API ..." -stop: +stop: ## Stop the application @echo "Stopping ${SHORTNAME} ..." @docker stop ${SHORTNAME} > /dev/null 2>&1 || : -tag: +tag: ## Display the Docker image tag @echo ${TAG} -test: assets - @echo "Running tests ..." +test: ## Run unit tests + @echo "Running unit tests ..." +# Run Rails tests @${RAILS} test -vars: +update: ## Review and update dependencies interactively + @echo "Checking for outdated dependencies..." + @if [ -f package.json ]; then \ + echo "Running yarn upgrade-interactive..."; \ + yarn upgrade-interactive; \ + fi + @echo "Running bundle outdated to check Ruby gems..." + @bundle outdated --only-explicit + +vars: ## Display environment variables @echo "Docker: ${REPO}:${TAG}" @echo "ACCOUNT = ${ACCOUNT}" @echo "ALPINE_VERSION = ${ALPINE_VERSION}" @@ -131,5 +162,5 @@ vars: @echo "TAG = ${TAG}" @echo "VERSION = ${VERSION}" -version: +version: ## Display the application version @echo ${VERSION} diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 2e77cd6d..6e518ded 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,6 +12,7 @@ // //= require jquery //= require jquery_ujs +//= require popper //= require bootstrap //= require lr_common_styles/application //= require_tree . diff --git a/app/assets/stylesheets/_search-form.scss b/app/assets/stylesheets/_search-form.scss deleted file mode 100644 index 61b847f3..00000000 --- a/app/assets/stylesheets/_search-form.scss +++ /dev/null @@ -1,8 +0,0 @@ -.search-form-actions { - margin-top: 1.5em; - display: flex; - - > * { - margin-left: 0.75em; - } -} diff --git a/app/assets/stylesheets/_workflow-actions.scss b/app/assets/stylesheets/_workflow-actions.scss index dfab7a11..d1820e83 100644 --- a/app/assets/stylesheets/_workflow-actions.scss +++ b/app/assets/stylesheets/_workflow-actions.scss @@ -1,8 +1,29 @@ -.workflow-actions { +.workflow-actions, +.search-form-actions { + margin-block: 1.0em; display: flex; - justify-content: flex-end; + flex-wrap: wrap; + gap: 0.5rem 1.0rem; + justify-content: center; - > * { - margin-left: 0.75em; + .button { + flex: 0 0 auto; + width: 90%; } -} \ No newline at end of file + + .search-form-action { + > .button { + width: auto; + } + } + + @media (min-width: 576px) { + row-gap: 0; + justify-content: flex-end; + + .button { + width: auto; + } + } + +} diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 0ebdd885..5e93ea80 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -2,15 +2,12 @@ *= require jquery-ui */ -@import - "govuk-template", - "govuk-elements", - "bootstrap-sprockets", - "bootstrap", - "font-awesome", - "lr_common_styles/lr-common", - "gov-uk-tweaks", - "ppd", - 'search-form', - 'search-results', - 'workflow-actions'; +@import "govuk-template"; +@import "govuk-elements"; +@import "bootstrap"; +@import "font-awesome"; +@import "lr_common_styles/lr-common"; +@import "gov-uk-tweaks"; +@import "ppd"; +@import 'search-results'; +@import 'workflow-actions'; diff --git a/app/assets/stylesheets/ppd.scss b/app/assets/stylesheets/ppd.scss index b11af3e5..96282ab3 100644 --- a/app/assets/stylesheets/ppd.scss +++ b/app/assets/stylesheets/ppd.scss @@ -1,9 +1,11 @@ +@use 'sass:color'; + $lr-logo-grey: #a7a5a6; @media (min-width: 641px) { .lr main { - font-size: 16px; - line-height: 1.31578947; + font-size: 16px; + line-height: 1.31578947; } } @@ -14,10 +16,11 @@ $lr-logo-grey: #a7a5a6; .control-legend { border: none; - font-size: 16px; + font-size: 1.6rem; line-height: 1.31578947; font-family: "nta", Arial, sans-serif; font-weight: bold; + @media (max-width: 768px) { margin-block-end: 0; } @@ -32,7 +35,8 @@ $lr-logo-grey: #a7a5a6; margin-top: 10px; } - h2, h3 { + h2, + h3 { margin-top: 8px; } @@ -81,20 +85,20 @@ $lr-logo-grey: #a7a5a6; } } - .search-selection > span { + .search-selection>span { margin-left: 10px; } - .detailed-address { + .detailed-address { table { td { border: 0; padding: 2px; } - .property-details-field-title { - padding-right: 10px; - } + .property-details-field-title { + padding-right: 10px; + } } @@ -114,7 +118,10 @@ $lr-logo-grey: #a7a5a6; } .ppd-results { - h2, h3, h4 { + + h2, + h3, + h4 { font-family: Arial, sans-serif; } @@ -173,7 +180,7 @@ $lr-logo-grey: #a7a5a6; } .transaction-category { - background-color: lighten( $lr-logo-grey, 20% ); + background-color: color.adjust($lr-logo-grey, $lightness: 20%); padding: 3px; border-radius: 3px; } @@ -190,7 +197,7 @@ $lr-logo-grey: #a7a5a6; } .social-media { - > div { + >div { display: inline-block; vertical-align: top !important; height: 20px; @@ -206,6 +213,7 @@ $lr-logo-grey: #a7a5a6; dt { width: 60px; } + dd { margin-left: 80px; } @@ -229,8 +237,209 @@ $lr-logo-grey: #a7a5a6; .footnotes { p { margin-inline: 15px; + @media (min-width: 768px) { margin-inline: 0; } } } + + +// Style Updates 2026 Post-Sass Migration + +h1, +.h1 { + font-size: 3.6rem; +} + +h2, +.h2 { + font-size: 3rem; +} + +h3, +.h3 { + font-size: 2.4rem; +} + +h4, +.h4 { + font-size: 2rem; +} + +h5, +.h5 { + font-size: 1.6rem; +} + +h6, +.h6 { + font-size: 1.4rem; +} + + +label { + display: inline-block; + max-width: 100%; + margin-bottom: 5px; + font-weight: 700; + + &:has(input[type="checkbox"]), + &:has(input[type="radio"]) { + font-weight: 400; + } + + &:has(input[type="date"]) { + line-height: 2; + } +} + +@media (max-width: 768px) { + .control-legend { + margin-block-end: 0; + padding-block-end: 0.75rem; + } +} + +@media (min-width: 768px) { + + .form-horizontal { + .form-group { + display: flex; + gap: 3rem; + margin-right: -15px; + margin-left: -15px; + } + + .control-label { + line-height: 2.2; + margin-bottom: 0; + text-align: right; + } + + .radio, + .checkbox { + min-height: 27px; + } + + .radio, + .checkbox, + .radio-inline, + .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; + } + + } +} + +.lr form.ppd ul.list-inline { + display: inline-flex; + gap: 0.25rem 1.5rem; + flex-wrap: wrap +} + + +.form-control { + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 1.4rem; + line-height: 1.428571429; + color: #555555; + background-color: #fff; + background-image: none; +} + +.form-control::-webkit-input-placeholder { + color: #999; +} + +.input-group .input-group-addon { + @extend .input-group-text !optional; + font-size: 1.4rem; + padding-inline: 1.2rem; +} + +// Modal styles +@media (min-width: 768px) { + .modal { + --bs-modal-width: 600px; + --bs-modal-padding: 1.75rem; + + .btn { + font-size: 1.4rem; + } + } + + .modal-dialog { + width: 600px; + margin: 30px auto; + } +} + +.modal-header { + flex-direction: row-reverse; + justify-content: space-between; + + button.close { + align-self: flex-start; + } +} + +.modal-footer { + align-items: end; +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + appearance: none; +} + +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: 0.2; +} + +#help-modal .dl-horizontal { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 1.5rem; + margin-block-end: 2rem; + + dt { + flex: 0 0 10%; + max-width: 10%; + font-weight: 700; + text-align: end; + } + + dd { + flex: 0 0 75%; + max-width: 75%; + margin-left: 0; + } +} + +// Lists +.list-bullet { + list-style-position: outside; +} + +.cookie-banner { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: initial; + padding-inline: 3rem; + border-bottom: 1px solid #e5e5e5; +} diff --git a/app/lib/version.rb b/app/lib/version.rb index c7fdb888..dbd116ff 100644 --- a/app/lib/version.rb +++ b/app/lib/version.rb @@ -2,8 +2,8 @@ module Version MAJOR = 2 - MINOR = 2 - PATCH = 3 + MINOR = 3 + PATCH = 0 SUFFIX = nil VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}#{SUFFIX && ".#{SUFFIX}"}".freeze end diff --git a/app/views/exceptions/error_page.html.haml b/app/views/exceptions/error_page.html.haml index 1b09fecb..e565105f 100644 --- a/app/views/exceptions/error_page.html.haml +++ b/app/views/exceptions/error_page.html.haml @@ -1,57 +1,65 @@ - puts "Rendering error page with status: #{status.inspect}" if Rails.env.development? - content_for(:current_environment_title, EnvironmentHelper.environment_title) -%article.u-clear - - if status == 400 - %h1.o-heading--1 Request not understood - %p - We're sorry, but the request you made was not understood. If you are requesting - data via a script or program, please check the URL parameters. If you see this - message as a result of using the HPI or PPD applications, please let us - know so that we can correct the problem. - - - elsif status == 403 - %h1.o-heading--1 Forbidden - - %p - We're sorry, but it seems you don't have permission to access this resource. - Please check the spelling of the page address (URL). If you require further - assistance, please see the contact details below. - - - elsif status == 404 - %h1.o-heading--1 Page not found - - %p - We're sorry, but the web page you requested is not present on our server. - Please check the spelling of the page address (URL). If you require further - assistance, please see the contact details below. - - - else - %h1.o-heading--1 Application error - - %p - We're very sorry, but the request you just made resulted in an internal error - in the application. If this problem persists, please use one of the contact - methods below to report the problem to us, so that we can resolve it and - help you get the data you require. - - - if sentry_code - %h2.o-heading--3 Reference code - %p - If you need to contact support staff about this issue, please use the following - code to identify the problem: - %code - = sentry_code - - %h2.o-heading--2 Who to contact - %ul.list.list-bullet - %li - If you are unable to access the data, please - %a{ href: '//site.landregistry.gov.uk/contact-us/form' } - fill in our contact form. - %li - For general transaction data enquiries, email - = mail_to('DRO@landregistry.gov.uk') - %li - For general price paid data enquiries, contact - = mail_to(Rails.application.config.contact_email_address) +.row.mx-3.my-5 + .col-md-12 + %article.u-clear + - if status == 400 + %h1.o-heading--1 Request not understood + %p + We're sorry, but the request you made was not understood. If you are requesting + data via a script or program, please check the URL parameters. If you see this + message as a result of using the HPI or PPD applications, please let us + know so that we can correct the problem. + + - elsif status == 403 + %h1.o-heading--1 Request denied + + %p + We're sorry, but it seems you don't have permission to access this resource. + Please check the spelling of the page address (URL). If you require further + assistance, please see the contact details below. + + - elsif status == 404 + %h1.o-heading--1 Page not found + + %p + We're sorry, but the web page you requested is not present on our server. + Please check the spelling of the page address (URL). If you require further + assistance, please see the contact details below. + + - elsif status == 422 + %h1.o-heading--1 The change you wanted was rejected. + %p + Maybe you tried to change something you didn't have access to? If you are + the application owner, check the logs for more information. + + - else + %h1.o-heading--1 Application error + + %p + We're very sorry, but the request you just made resulted in an internal error + in the application. If this problem persists, please use one of the contact + methods below to report the problem to us, so that we can resolve it and + help you get the data you require. + + - if sentry_code + %h2.o-heading--3 Reference code + %p + If you need to contact support staff about this issue, please use the following + code to identify the problem: + %code + = sentry_code + + %h2.o-heading--2 Who to contact + %ul.list.list-bullet + %li + If you are unable to access the data, please + %a{ href: '//site.landregistry.gov.uk/contact-us/form' } + fill in our contact form. + %li + For general transaction data enquiries, email + = mail_to('DRO@landregistry.gov.uk') + %li + For general price paid data enquiries, contact + = mail_to(Rails.application.config.contact_email_address) diff --git a/app/views/ppd/_bookmark_modal.html.haml b/app/views/ppd/_bookmark_modal.html.haml index c208551d..74eb376b 100644 --- a/app/views/ppd/_bookmark_modal.html.haml +++ b/app/views/ppd/_bookmark_modal.html.haml @@ -3,13 +3,13 @@ #bookmark-modal.modal #bookmark-dialog.modal-dialog{role: "dialog", "aria-labelledby": "bookmark-link", "aria-modal": "true"} .modal-content - .modal-header - %button.close{ type: "button", data: {dismiss: "modal"}, aria: {hidden: "true"}} + .modal-header.ps-5 + %button.close{ type: "button", data: { "bs-dismiss": "modal"}, aria: {hidden: "true"}} × #bookmark-link %h2.modal-title Link to the current search - .modal-body + .modal-body.px-5 %p You can copy the current search settings to save them as a bookmark, or share with other people. Just-press @@ -25,7 +25,7 @@ %a.twitter-share-button{ href: "https://twitter.com/share", data: {url: "", text: "Open data from Land Registry", hashtags: "opendata"}} Tweet - .modal-footer + .modal-footer.px-5 .footer-row - %button.btn.btn-default{ type: "button", data: {dismiss: "modal"} } + %button.btn.btn-outline-secondary{ type: "button", data: { "bs-dismiss": "modal"} } OK diff --git a/app/views/ppd/_help_modal.html.haml b/app/views/ppd/_help_modal.html.haml index 0747db80..96f36e72 100644 --- a/app/views/ppd/_help_modal.html.haml +++ b/app/views/ppd/_help_modal.html.haml @@ -3,13 +3,13 @@ #help-modal.modal #help-dialog.modal-dialog{role: "dialog", "aria-labelledby": "help-title", "aria-modal": "true"} .modal-content - .modal-header - %button.close{ type: "button", data: {dismiss: "modal"}, aria: {hidden: "true"}} + .modal-header.ps-5 + %button.close{ type: "button", data: { "bs-dismiss": "modal"}, aria: {hidden: "true"}} × #help-title %h2.modal-title Help and suggestions - .modal-body + .modal-body.px-5 %h3 Troubleshooting guide %p See the @@ -40,9 +40,9 @@ %p If you have additional questions, or you have feedback on this beta service, please email - .email-address= mail_to(Rails.application.config.contact_email_address) + %span.email-address= mail_to(Rails.application.config.contact_email_address) - .modal-footer + .modal-footer.px-5 .footer-row - %button.btn.btn-default{ type: "button", data: {dismiss: "modal"} } + %button.btn.btn-outline-secondary{ type: "button", data: { "bs-dismiss": "modal"} } OK diff --git a/app/views/ppd/index.html.haml b/app/views/ppd/index.html.haml index 8a44e169..6af79078 100644 --- a/app/views/ppd/index.html.haml +++ b/app/views/ppd/index.html.haml @@ -3,7 +3,7 @@ = content_for(:title, "Search the price paid dataset") -.row +.row.px-5 .col-sm-12 .pull-right.search-form-actions .search-form-action @@ -15,54 +15,54 @@ %i.fa.fa-refresh reset the form -.row +.row.px-5 %h1.col-md-12 = "#{yield(:title)}:" %p.col-md-12 Enter one or more search terms to locate the property transactions you are interested in. -.row +.row.px-5 .col-md-12 =form_tag( {controller: :search, action: :create}, {role: "form", class: "ppd form form-horizontal"} ) do - .form-group - %label.col-sm-4.control-label{ for: "paon" } Building name or number - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "paon" } Building name or number + .col-md-8 %input#paon.form-control{ type: "text", autocomplete: "on", name: "paon", value: strip_tags(@preferences.param( :paon )), placeholder: "For example: Rose Cottage or 17" } - .form-group - %label.col-sm-4.control-label{ for: "street" } Street - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "street" } Street + .col-md-8 %input#street.form-control{ type: "text", autocomplete: "street-address", name: "street", value: strip_tags(@preferences.param( :street )), placeholder: "Use the full name, or just part of it e.g: Harbour Road or Colston" } - .form-group - %label.col-sm-4.control-label{ for: "town" } Town or city - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "town" } Town or city + .col-md-8 %input#town.form-control{ type: "text", autocomplete: "address-level2", name: "town", value: strip_tags(@preferences.param( :town )), placeholder: "For example: Plymouth" } - .form-group - %label.col-sm-4.control-label{ for: "district" } District - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "district" } District + .col-md-8 %input#district.form-control{ type: "text", autocomplete: "address-level3", name: "district", value: strip_tags(@preferences.param( :district )), placeholder: "For example: City of Westminster" } - .form-group - %label.col-sm-4.control-label{ for: "county" } County - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "county" } County + .col-md-8 %input#county.form-control{ type: "text", autocomplete: "county", name: "county", value: strip_tags(@preferences.param( :county )), placeholder: "For example: Devon" } - .form-group - %label.col-sm-4.control-label{ for: "locality" } Locality - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "locality" } Locality + .col-md-8 %input#locality.form-control{ type: "text", autocomplete: "on", name: "locality", value: strip_tags(@preferences.param( :locality )), placeholder: "For example: Thurloxton" } - .form-group - %label.col-sm-4.control-label{ for: "postcode" } Postcode - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "postcode" } Postcode + .col-md-8 %input#postcode.form-control{ type: "text", autocomplete: "postal-code", name: "postcode", value: strip_tags(@preferences.param( :postcode )), placeholder: "Use a full postcode, or just the first group e.g. PL6 5WS or PL6." } - %fieldset.form-group - %legend.control-legend.col-sm-4.control-label{ for: "ptype" } Property type - .col-sm-8 + %fieldset.form-group.gx-5 + %legend.control-legend.col-md-4.control-label{ for: "ptype" } Property type + .col-md-8 %ul.list-inline %li .checkbox @@ -90,9 +90,9 @@ %input{ type: "checkbox", name: "ptype[]", value: "lrcommon:otherPropertyType", checked: @preferences.display_checked?( :ptype, "lrcommon:otherPropertyType") } other - %fieldset.form-group - %legend.control-legend.col-sm-4.control-label{ for: "nb" } New build? - .col-sm-8 + %fieldset.form-group.gx-5 + %legend.control-legend.col-md-4.control-label{ for: "nb" } New build? + .col-md-8 %ul.list-inline %li .checkbox @@ -105,9 +105,9 @@ %input{ type: "checkbox", name: "nb[]", value: "false", checked: @preferences.display_checked?( :nb, "false" ) } not new-build - %fieldset.form-group - %legend.control-legend.col-sm-4.control-label{ for: "et" } Estate type - .col-sm-8 + %fieldset.form-group.gx-5 + %legend.control-legend.col-md-4.control-label{ for: "et" } Estate type + .col-md-8 %ul.list-inline %li .checkbox @@ -120,9 +120,9 @@ %input{ type: "checkbox", name: "et[]", value: "lrcommon:leasehold", checked: @preferences.display_checked?( :et, "lrcommon:leasehold" ) } leasehold - %fieldset.form-group - %legend.control-legend.col-sm-4.control-label{ for: "tc" } Transaction category - .col-sm-8 + %fieldset.form-group.gx-5 + %legend.control-legend.col-md-4.control-label{ for: "tc" } Transaction category + .col-md-8 %ul.list-inline %li .checkbox @@ -135,11 +135,11 @@ %input{ type: "checkbox", name: "tc[]", value: "ppd:additionalPricePaidTransaction", checked: @preferences.display_checked?( :tc, "ppd:additionalPricePaidTransaction" ) } additional - .form-group - %label.col-sm-4.control-label{ for: "min_price" } Minimum price - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "min_price" } Minimum price + .col-md-8 .row - .col-sm-4 + .col-md-4 .input-group %span.input-group-addon £ @@ -149,14 +149,14 @@ value: strip_tags(@preferences.param( :min_price )), spellcheck: false, } - .col-sm-8.hidden.validation-warning + .col-md-8.hidden.validation-warning %p.bg-warning Please enter a valid numerical value, or leave blank - .form-group - %label.col-sm-4.control-label{ for: "max_price" } Maximum price - .col-sm-8 + .form-group.gx-5 + %label.col-md-4.control-label{ for: "max_price" } Maximum price + .col-md-8 .row - .col-sm-4 + .col-md-4 .input-group %span.input-group-addon £ @@ -166,13 +166,13 @@ value: strip_tags(@preferences.param( :max_price )), spellcheck: false, } - .col-sm-8.hidden.validation-warning + .col-md-8.hidden.validation-warning %p.bg-warning Please enter a valid numerical value, or leave blank - .form-group - %label.col-sm-4.control-label.control-label-adjust Date - .col-sm-8 + %fieldset.form-group.gx-5 + %legend.control-legend.col-md-4.control-label{ for: "dates" } Date + .col-md-8 %ul.list-inline %li %div @@ -185,9 +185,9 @@ latest: %input{ type: 'date', name: :max_date, value: @preferences.param( :max_date ), min: "1995-01-01", max: Date.today.iso8601 } - %fieldset.form-group - %legend.control-legend.col-sm-4.control-label{ for: "limit" } How many results? - .col-sm-8 + %fieldset.form-group.gx-5 + %legend.control-legend.col-md-4.control-label{ for: "limit" } How many results? + .col-md-8 %ul.list-inline %li .radio diff --git a/app/views/ppd_data/_download_options.html.haml b/app/views/ppd_data/_download_options.html.haml index 47210151..eec9a4fb 100644 --- a/app/views/ppd_data/_download_options.html.haml +++ b/app/views/ppd_data/_download_options.html.haml @@ -7,7 +7,7 @@ a bug, or that the format requested is not one that is currently supported. - else .download - .row + .row.px-5 .col-md-12 = render partial: "ppd/workflow_action_buttons", locals: {no_download: true, no_print: true, no_help: true, no_bookmark: true} %h1 @@ -15,7 +15,7 @@ .row.spacer - .row + .row.px-5 .col-md-12 %table.table %thead @@ -95,7 +95,7 @@ %i.fa.fa-eye view SPARQL query - .row.footnotes + .row.footnotes.px-5 %p %a#note1{href:"#note1Ref"} %strong Note 1 diff --git a/app/views/search/_search_results.html.haml b/app/views/search/_search_results.html.haml index eec8dd55..6a755ee0 100644 --- a/app/views/search/_search_results.html.haml +++ b/app/views/search/_search_results.html.haml @@ -2,12 +2,17 @@ = content_for(:title, "Search results") - sr = @query_command.search_results -= render partial: "ppd/workflow_action_buttons", locals: {no_results: true, no_print: true} -%h1 - = yield(:title) +.row.px-5 + .col-md-12 + = render partial: "ppd/workflow_action_buttons", locals: {no_results: true, no_print: true} + +.row.px-5 + .col-md-12 + %h1.px-5 + = yield(:title) -.search-summary +.search-summary.mx-5 %p #{sr&.summarise} by searching for: %ul.search-terms.list.list-bullet @@ -41,7 +46,7 @@ download the data onto your computer. -%ul.list-unstyled.ppd-results +%ul.list-unstyled.ppd-results.mx-5 - result = nil - sr&.each_property_address do |results| - previous_result = result diff --git a/config/application.rb b/config/application.rb index 5c3d813d..4b7c1021 100644 --- a/config/application.rb +++ b/config/application.rb @@ -3,7 +3,6 @@ require File.expand_path('boot', __dir__) # Pick the frameworks you want: -# require "active_record/railtie" require 'action_controller/railtie' require 'action_mailer/railtie' require 'sprockets/railtie' @@ -35,24 +34,33 @@ class Application < Rails::Application # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de + # Quiet SASS deprecation warnings coming from dependencies + config.sass.quiet_deps = true + # Silence @import deprecation warnings during migration to @use/@forward + # See: https://sass-lang.com/d/import + config.sass.silence_deprecations = ['import'] + # Add fonts path to asset pipeline config.assets.paths << Rails.root.join('app/assets/fonts') end end -# Monkey-patch the bit of Rails that emits the start-up log message, so that it -# is written out in JSON format that our combined logging service can handle +# Monkey-patch the bit of Rails that emits the start-up log message, so +# that it is written out in JSON format that our combined logging +# service can handle module Rails # :nodoc: module Command # :nodoc: class ServerCommand def print_boot_information(server, url) - msg = { + msg = "Starting #{server} Rails #{Rails.version} in #{Rails.env}" + msg += " on #{url}" if url + info = { ts: DateTime.now.utc.strftime('%FT%T.%3NZ'), level: 'INFO', - message: "Starting #{server} Rails #{Rails.version} in #{Rails.env} #{url}" + message: msg } - say msg.to_json + say info.to_json end end end diff --git a/config/environments/development.rb b/config/environments/development.rb index ea5b9fc4..856dc4b2 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -38,6 +38,9 @@ # Don't print a log message every time an asset file is loaded config.assets.quiet = true + # Enable SASS source maps in development for easier debugging + config.sass.inline_source_maps = true + # Tag rails logs with useful information config.log_tags = %i[subdomain request_id request_method] # When sync mode is true, all output is immediately flushed to the underlying diff --git a/config/environments/production.rb b/config/environments/production.rb index fd9b0202..df4ff2b3 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -37,6 +37,12 @@ # yet still be able to expire them through the digest params. config.assets.digest = true + # `config.sass.style` has been deprecated in favor of `config.assets.css_compressor` + # Set SASS output style to compressed for smaller file sizes + config.sass.style = :compressed + # SASS source maps are disabled in production for performance + config.sass.inline_source_maps = false + # `config.assets.precompile` and `config.assets.version` have moved to # config/initializers/assets.rb diff --git a/config/initializers/autoprefixer.rb b/config/initializers/autoprefixer.rb new file mode 100644 index 00000000..48507575 --- /dev/null +++ b/config/initializers/autoprefixer.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Configure Autoprefixer to generate source maps for easier debugging of CSS +# See: https://github.com/tablecheck/dartsass-sprockets/issues/23#issuecomment-2408131105 +class AutoprefixerWithSourcemap < AutoprefixerRails::Sprockets + def self.run(filename, css) + output = "#{filename.chomp(File.extname(filename))}.css" + + # If you want this nice an generic, you could check `css` for the presence + # of an inline source map, and set the `map` argument based on that + # instead of always setting it to `true`. + result = @processor.process(css, from: filename, to: output, map: true) + + result.warnings.each do |warning| + warn "autoprefixer: #{warning}" + end + + result.css + end + + def self.use_bundle_processor? + ::Sprockets::VERSION.to_f >= 4 + end + + def self.install(env) + if use_bundle_processor? + env.register_bundle_processor('text/css', self) + else + env.register_postprocessor('text/css', self) + end + end + + def self.uninstall(env) + if use_bundle_processor? + env.unregister_bundle_processor('text/css', self) + else + env.unregister_postprocessor('text/css', self) + end + end +end + +Rails.application.config.assets.configure do |env| + AutoprefixerRails.uninstall(env) + AutoprefixerWithSourcemap.register_processor(AutoprefixerRails.processor({})) + AutoprefixerWithSourcemap.install(env) +end