diff --git a/Gemfile.lock b/Gemfile.lock index 05b2eed76..27a8a6199 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,7 +100,7 @@ GEM rails-html-sanitizer (~> 1.6) active_material (2.1.4) active_skin (0.0.13) - activeadmin (3.2.5) + activeadmin (3.3.0) arbre (~> 1.2, >= 1.2.1) csv formtastic (>= 3.1) @@ -317,12 +317,13 @@ GEM activerecord (>= 7.0, < 8.1) activesupport (>= 7.0, < 8.1) request_store (~> 1.0) - google-cloud-core (1.7.1) + google-cloud-core (1.8.0) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) - google-cloud-env (2.2.1) + google-cloud-env (2.2.2) + base64 (~> 0.2) faraday (>= 1.0, < 3.a) - google-cloud-errors (1.4.0) + google-cloud-errors (1.5.0) google-cloud-location (0.10.0) gapic-common (>= 0.25.0, < 2.a) google-cloud-errors (~> 1.0) @@ -330,7 +331,7 @@ GEM google-cloud-core (~> 1.6) google-cloud-translate-v2 (>= 0.0, < 2.a) google-cloud-translate-v3 (>= 0.11, < 2.a) - google-cloud-translate-v2 (1.0.1) + google-cloud-translate-v2 (1.1.0) faraday (>= 1.0, < 3.a) google-cloud-core (~> 1.6) googleapis-common-protos (>= 1.3.10, < 2.a) @@ -346,10 +347,10 @@ GEM google-cloud-errors (~> 1.0) grpc-google-iam-v1 (~> 1.1) google-logging-utils (0.1.0) - google-protobuf (4.29.3) + google-protobuf (4.30.1) bigdecimal rake (>= 13) - google-protobuf (4.29.3-x86_64-linux) + google-protobuf (4.30.1-x86_64-linux) bigdecimal rake (>= 13) googleapis-common-protos (1.6.0) @@ -358,7 +359,7 @@ GEM grpc (~> 1.41) googleapis-common-protos-types (1.18.0) google-protobuf (>= 3.18, < 5.a) - googleauth (1.13.1) + googleauth (1.14.0) faraday (>= 1.0, < 3.a) google-cloud-env (~> 2.2) google-logging-utils (~> 0.1) @@ -368,10 +369,10 @@ GEM signet (>= 0.16, < 2.a) groupdate (6.5.1) activesupport (>= 7) - grpc (1.70.1) + grpc (1.71.0) google-protobuf (>= 3.25, < 5.0) googleapis-common-protos-types (~> 1.0) - grpc (1.70.1-x86_64-linux) + grpc (1.71.0-x86_64-linux) google-protobuf (>= 3.25, < 5.0) googleapis-common-protos-types (~> 1.0) grpc-google-iam-v1 (1.9.0) @@ -413,7 +414,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (2.10.1) + json (2.10.2) jsonapi-resources (0.9.12) activerecord (>= 4.1) concurrent-ruby @@ -445,7 +446,7 @@ GEM railties (>= 6.1) rexml lint_roller (1.1.0) - llhttp-ffi (0.5.0) + llhttp-ffi (0.5.1) ffi-compiler (~> 1.0) rake (~> 13.0) logger (1.6.6) @@ -462,13 +463,13 @@ GEM mime-types (3.6.0) logger mime-types-data (~> 3.2015) - mime-types-data (3.2025.0220) - mini_magick (5.1.2) + mime-types-data (3.2025.0304) + mini_magick (5.2.0) benchmark logger mini_mime (1.1.5) mini_portile2 (2.8.8) - minitest (5.25.4) + minitest (5.25.5) mjml-rails (4.14.1) msgpack (1.8.0) multi_json (1.15.0) @@ -490,12 +491,12 @@ GEM net-protocol net-ssh (7.3.0) nio4r (2.7.4) - nokogiri (1.18.3) + nokogiri (1.18.4) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.18.3-x86_64-linux-gnu) + nokogiri (1.18.4-x86_64-linux-gnu) racc (~> 1.4) - oj (3.16.9) + oj (3.16.10) bigdecimal (>= 3.0) ostruct (>= 0.2) oj_mimic_json (1.0.1) @@ -507,7 +508,7 @@ GEM activerecord (>= 6.1) request_store (~> 1.4) parallel (1.26.3) - parallel_tests (4.9.1) + parallel_tests (5.1.0) parallel paranoia (3.0.1) activerecord (>= 6, < 8.1) @@ -527,7 +528,7 @@ GEM puma (6.6.0) nio4r (~> 2.0) racc (1.8.1) - rack (3.0.12) + rack (3.0.14) rack-cors (2.0.2) rack (>= 2.0.0) rack-mini-profiler (2.3.4) @@ -581,7 +582,7 @@ GEM i18n rdoc (6.12.0) psych (>= 4.0.0) - redcarpet (3.6.0) + redcarpet (3.6.1) redis (5.4.0) redis-client (>= 0.22.0) redis-actionpack (5.5.0) @@ -591,7 +592,7 @@ GEM redis-activesupport (5.3.0) activesupport (>= 3, < 8) redis-store (>= 1.3, < 2) - redis-client (0.23.2) + redis-client (0.24.0) connection_pool redis-rack (3.0.0) rack-session (>= 0.2.0) @@ -648,9 +649,10 @@ GEM rswag-ui (2.16.0) actionpack (>= 5.2, < 8.1) railties (>= 5.2, < 8.1) - rubocop (1.71.2) + rubocop (1.73.2) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) @@ -658,16 +660,18 @@ GEM rubocop-ast (>= 1.38.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.38.0) + rubocop-ast (1.39.0) parser (>= 3.3.1.0) - rubocop-performance (1.23.1) - rubocop (>= 1.48.1, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rails (2.29.1) + rubocop-performance (1.24.0) + lint_roller (~> 1.1) + rubocop (>= 1.72.1, < 2.0) + rubocop-ast (>= 1.38.0, < 2.0) + rubocop-rails (2.30.3) activesupport (>= 4.2.0) + lint_roller (~> 1.1) rack (>= 1.1) - rubocop (>= 1.52.0, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) + rubocop (>= 1.72.1, < 2.0) + rubocop-ast (>= 1.38.0, < 2.0) ruby-graphviz (1.2.5) rexml ruby-progressbar (1.13.0) @@ -693,10 +697,10 @@ GEM sendgrid-ruby (~> 6.4) sendgrid-ruby (6.7.0) ruby_http_client (~> 3.4) - sentry-rails (5.22.4) + sentry-rails (5.23.0) railties (>= 5.0) - sentry-ruby (~> 5.22.4) - sentry-ruby (5.22.4) + sentry-ruby (~> 5.23.0) + sentry-ruby (5.23.0) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) shoulda-matchers (4.0.1) @@ -733,18 +737,18 @@ GEM net-ssh (>= 2.8.0) ostruct ssrf_filter (1.2.0) - standard (1.45.0) + standard (1.47.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) - rubocop (~> 1.71.0) + rubocop (~> 1.73.0) standard-custom (~> 1.0.0) - standard-performance (~> 1.6) + standard-performance (~> 1.7) standard-custom (1.0.2) lint_roller (~> 1.0) rubocop (~> 1.50) - standard-performance (1.6.0) + standard-performance (1.7.0) lint_roller (~> 1.1) - rubocop-performance (~> 1.23.0) + rubocop-performance (~> 1.24.0) stringio (3.1.5) super_diff (0.15.0) attr_extras (>= 6.2.4) @@ -764,7 +768,7 @@ GEM unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) uniform_notifier (1.16.0) - uri (1.0.2) + uri (1.0.3) useragent (0.16.11) warden (1.2.9) rack (>= 2.0.9) @@ -774,7 +778,7 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webmock (3.25.0) + webmock (3.25.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) diff --git a/app/admin/components/dialog.rb b/app/admin/components/dialog.rb new file mode 100644 index 000000000..df76a32f0 --- /dev/null +++ b/app/admin/components/dialog.rb @@ -0,0 +1,32 @@ +module Admin + module Components + class Header < Arbre::HTML::Tag + builder_method :html5_header + end + + class Dialog < Arbre::HTML::Tag + builder_method :dialog + attr_accessor :inner_content + + def build(attributes = {}) + title = attributes[:title] + super(attributes.except(:title)) + html5_header do + strong title if title.present? + button "X", title: "Close", class: "button close-dialog-button" + end + @inner_content = div + end + + def add_child(child) + if @inner_content + @inner_content.add_child child + else + super + end + end + + delegate :children?, to: :@inner_content + end + end +end diff --git a/app/admin/fmu.rb b/app/admin/fmu.rb index 559a14cbf..062edab43 100644 --- a/app/admin/fmu.rb +++ b/app/admin/fmu.rb @@ -69,7 +69,7 @@ def download_shapefiles(fmus) } end - sidebar "Shapefiles" do + sidebar "Shapefiles", only: :index do div do link_to "Download Filtered Shapefiles", download_filtered_shapefiles_admin_fmus_path( q: params[:q]&.to_unsafe_h @@ -101,29 +101,51 @@ def download_shapefiles(fmus) end show do - attributes_table do - row :id - row :name - row :forest_type - row :country - row :operator - row :certification_fsc - row :certification_pefc - row :certification_olb - row :certification_pafc - row :certification_fsc_cw - row :certification_tlv - row :certification_ls - if resource.geojson && resource.centroid.present? - row :map do |r| - render partial: "map", locals: {center: [r.centroid.x, r.centroid.y], center_marker: false, geojson: r.geojson, bbox: r.bbox} + columns class: "d-flex" do + column class: "flex-1" do + attributes_table do + row :id + row :name + row :forest_type + row :country + row :operator + + if resource.geojson && resource.centroid.present? + row :map do |r| + render partial: "map", locals: {center: [r.centroid.x, r.centroid.y], center_marker: false, geojson: r.geojson, bbox: r.bbox} + end + end + if resource.geojson + row(:geojson) do + dialog id: "geojson_modal", title: Fmu.human_attribute_name(:geojson) do + resource.geojson + end + link_to t("active_admin.view"), "javascript:void(0)", onclick: "document.querySelector('#geojson_modal').showModal()" + end + row(:properties) do + dialog id: "properties_modal", title: Fmu.human_attribute_name(:properties) do + resource.properties + end + link_to t("active_admin.view"), "javascript:void(0)", onclick: "document.querySelector('#properties_modal').showModal()" + end + end + row :created_at + row :updated_at + row :deleted_at + end + end + + column max_width: "250px" do + attributes_table title: t("active_admin.fmus_page.certification") do + row :certification_fsc + row :certification_pefc + row :certification_olb + row :certification_pafc + row :certification_fsc_cw + row :certification_tlv + row :certification_ls end end - row(:geojson) { |fmu| fmu.geojson.to_json } - row(:properties) { |fmu| fmu.geojson&.dig("properties")&.to_json } - row :created_at - row :updated_at - row :deleted_at end end diff --git a/app/assets/javascripts/active_admin.js b/app/assets/javascripts/active_admin.js index 0d5ba45a1..68dcd5fb3 100644 --- a/app/assets/javascripts/active_admin.js +++ b/app/assets/javascripts/active_admin.js @@ -2,6 +2,7 @@ //= require activeadmin_addons/all //= require access_control //= require editor +//= require dialog //= require users //= require rod //= require fmu diff --git a/app/assets/javascripts/dialog.js b/app/assets/javascripts/dialog.js new file mode 100644 index 000000000..35c74f101 --- /dev/null +++ b/app/assets/javascripts/dialog.js @@ -0,0 +1,25 @@ +function initializeDialog() { + document.querySelectorAll("dialog").forEach((dialog) => { + // close when clicking outside + dialog.addEventListener("mousedown", (event) => { + // Check if the click is on the backdrop (not the dialog content) + const dialogDimensions = dialog.getBoundingClientRect(); + if ( + event.clientX < dialogDimensions.left || + event.clientX > dialogDimensions.right || + event.clientY < dialogDimensions.top || + event.clientY > dialogDimensions.bottom + ) { + dialog.close(); + } + }); + + dialog.querySelectorAll(".close-dialog-button").forEach((button) => { + button.addEventListener("click", () => { + dialog.close(); + }); + }); + }); +} + +document.addEventListener("DOMContentLoaded", initializeDialog); diff --git a/app/assets/stylesheets/active_admin.scss b/app/assets/stylesheets/active_admin.scss index a305ced1b..c2f25fcc4 100644 --- a/app/assets/stylesheets/active_admin.scss +++ b/app/assets/stylesheets/active_admin.scss @@ -214,3 +214,39 @@ body.active_admin { display: none; } +dialog { + border: 0; + padding: 0; + + max-height: 80vh; + max-width: 70vw; + overflow-y: auto; + + header { + display: flex; + background-color: $panelHeaderBck; + color: #fff; + justify-content: space-between; + align-items: center; + padding: 10px; + + > strong { + font-size: 1.2em; + } + + .close-dialog-button { + cursor: pointer; + padding: 10px 15px; + margin-left: auto; + } + } + + > div { + padding: 10px; + } +} + +dialog::backdrop { + backdrop-filter: blur(2px); +} + diff --git a/app/models/operator_document_filter_tree.rb b/app/models/operator_document_filter_tree.rb index 4ad1486f6..bce7d7314 100644 --- a/app/models/operator_document_filter_tree.rb +++ b/app/models/operator_document_filter_tree.rb @@ -16,8 +16,6 @@ def tree } end - private - TYPES = [ {id: "OperatorDocumentCountry", name: I18n.t("operator_documents.filters.producer")}, {id: "OperatorDocumentFmu", name: I18n.t("operator_documents.filters.fmu")} @@ -36,6 +34,8 @@ def tree {id: 3, name: I18n.t("filters.other")} ].freeze + private + def legal_categories RequiredOperatorDocumentGroup.with_translations.where.not(id: required_operator_group_id_to_exclude).map do |x| { diff --git a/app/resources/v1/operator_document_country_resource.rb b/app/resources/v1/operator_document_country_resource.rb index bffea877b..ab001fc7a 100644 --- a/app/resources/v1/operator_document_country_resource.rb +++ b/app/resources/v1/operator_document_country_resource.rb @@ -16,8 +16,6 @@ def self.creatable_fields(context) super - [:fmu_id] end - def type - @model.type - end + delegate :type, to: :@model end end diff --git a/app/resources/v1/operator_document_fmu_resource.rb b/app/resources/v1/operator_document_fmu_resource.rb index f819da52c..8a8a930ce 100644 --- a/app/resources/v1/operator_document_fmu_resource.rb +++ b/app/resources/v1/operator_document_fmu_resource.rb @@ -4,8 +4,6 @@ module V1 class OperatorDocumentFmuResource < OperatorDocumentResource has_one :required_operator_document_fmu - def type - @model.type - end + delegate :type, to: :@model end end diff --git a/app/resources/v1/operator_resource.rb b/app/resources/v1/operator_resource.rb index e55990707..cc5611d2d 100644 --- a/app/resources/v1/operator_resource.rb +++ b/app/resources/v1/operator_resource.rb @@ -29,9 +29,7 @@ class OperatorResource < BaseResource before_create :set_active after_create :send_notification - def type - @model.type - end + delegate :type, to: :@model def set_active @model.is_active = false diff --git a/config/locales/en.yml b/config/locales/en.yml index c9d73f620..84b68dc5e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -330,6 +330,7 @@ en: indicator_apv: 'Indicator APV' law_details: 'Law details' fmus_page: + certification: Certification download_shapefile: 'Download shapefile' confirm_delete: 'Are you sure you want to delete this FMU?' operator_page: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a369d1cb7..e9d0e9fcd 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -362,6 +362,7 @@ fr: indicator_apv: 'Indicateur APV' law_details: 'Détails de la loi' fmus_page: + certification: Certification download_shapefile: 'Télécharger shapefile' confirm_delete: 'Êtes-vous sûr de vouloir supprimer cette FMU?' required_operator_document_page: diff --git a/lib/active_admin/filter_saver/controller.rb b/lib/active_admin/filter_saver/controller.rb index fd03fbaba..b35968880 100644 --- a/lib/active_admin/filter_saver/controller.rb +++ b/lib/active_admin/filter_saver/controller.rb @@ -8,10 +8,10 @@ module FilterSaver # @author David Daniell / тιηуηυмвєяѕ # rubocop:enable Style/AsciiComments module Controller - private - SAVED_FILTER_KEY = :last_search_filter + private + def restore_search_filters filter_storage = session[SAVED_FILTER_KEY] if params[:clear_filters].present?