diff --git a/app/controllers/admin/neighbourhoods_controller.rb b/app/controllers/admin/neighbourhoods_controller.rb index 596492864..e2b7790be 100644 --- a/app/controllers/admin/neighbourhoods_controller.rb +++ b/app/controllers/admin/neighbourhoods_controller.rb @@ -10,9 +10,10 @@ def index respond_to do |format| format.html format.json { render json: NeighbourhoodDatatable.new( - params, view_context: view_context, + params, + view_context: view_context, neighbourhoods: @neighbourhoods - ) + ) } end end diff --git a/app/datatables/neighbourhood_datatable.rb b/app/datatables/neighbourhood_datatable.rb index 44f525235..9533b6161 100644 --- a/app/datatables/neighbourhood_datatable.rb +++ b/app/datatables/neighbourhood_datatable.rb @@ -8,6 +8,7 @@ def view_columns unit_name: { source: 'Neighbourhood.unit_name' }, unit_code_key: { source: 'Neighbourhood.unit_code_key' }, unit_code_value: { source: 'Neighbourhood.unit_code_value' }, + parent_name: { source: 'Neighbourhood.parent_name' }, } end @@ -19,10 +20,7 @@ def data unit_name: record.unit_name, unit_code_key: record.unit_code_key, unit_code_value: record.unit_code_value, - # county: record.county, - # district: record.district, - # region: record.region, - # country: record.country + parent_name: record.parent_name, } end end diff --git a/app/helpers/sites_helper.rb b/app/helpers/sites_helper.rb new file mode 100644 index 000000000..d16655577 --- /dev/null +++ b/app/helpers/sites_helper.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module SitesHelper + def options_for_sites_neighbourhoods + # Remove the primary neighbourhood from the list + @all_neighbourhoods.filter { |e| e.name != '' } + .collect { |e| { name: e.contextual_name, id: e.id } } + end +end diff --git a/app/javascript/packs/admin.js b/app/javascript/packs/admin.js index a64688328..34019d7a6 100644 --- a/app/javascript/packs/admin.js +++ b/app/javascript/packs/admin.js @@ -1,6 +1,6 @@ -require("cocoon") -require("select2") require("datatables.net-bs4") +require("@nathanvda/cocoon") +require("select2") import 'bootstrap' import 'vue' @@ -12,7 +12,6 @@ import '../src/datatable.js' import '../src/opening-times.js' import '../src/ward-picker.js' - $(document).on('turbolinks:load', function () { $('body').init_behaviors() diff --git a/app/javascript/src/behaviors/all_behaviors.js b/app/javascript/src/behaviors/all_behaviors.js index 7727b7a74..88b7359f2 100644 --- a/app/javascript/src/behaviors/all_behaviors.js +++ b/app/javascript/src/behaviors/all_behaviors.js @@ -4,4 +4,5 @@ import './behaviors.collection.js' import './behaviors.neighbourhood.js' import './behaviors.partner.js' import './behaviors.place.js' +import './behaviors.site.js' import './behaviors.user.js' diff --git a/app/javascript/src/behaviors/behaviors.site.js b/app/javascript/src/behaviors/behaviors.site.js new file mode 100644 index 000000000..1ceae0ceb --- /dev/null +++ b/app/javascript/src/behaviors/behaviors.site.js @@ -0,0 +1,20 @@ +jQuery.extend(Behaviors, { + site: { + form: { + init: function() { + // If the sites neighbourhood's relation_type is primary, it generates a label + // with the class 'cocoon_delete-this'. This allows us to remove it from the form + // so it does not submit a primary relation as being a secondary one or remove it + $('.cocoon_delete-this').parents('.nested-fields').remove(); + + // Attach select2 to the current select2 nodes + $('.select2').each(function () { $(this).select2({ multiple: false }); }); + + // Attach select2 to all future select2 nodes + $('.sites_neighbourhoods').bind('cocoon:after-insert', function (_, element) { + $('.select2', element).select2({ multiple: false }); + }); + } + } + } +}); diff --git a/app/javascript/src/datatable.js b/app/javascript/src/datatable.js index d47f80272..8d6c35384 100644 --- a/app/javascript/src/datatable.js +++ b/app/javascript/src/datatable.js @@ -10,15 +10,23 @@ document.addEventListener("turbolinks:before-cache", function () { }); document.addEventListener('turbolinks:load', function () { - dataTable = $('#datatable').DataTable({ - "processing": true, - "serverSide": true, - "pageLength": 15, - "ajax": { - "url": $('#datatable').data('source') - }, - "pagingType": "full_numbers", - // Column spec is loaded from a script tag in the view - "columns": columns - }) + try { + dataTable = $('#datatable').DataTable({ + "processing": true, + "serverSide": true, + "pageLength": 15, + "ajax": { + "url": $('#datatable').data('source') + }, + "pagingType": "full_numbers", + // Column spec is loaded from a script tag in the view + "columns": columns + }) + } catch (e) { + // On pages where DataTables shouldn't be used, columns is not defined. + // This catches that and stops it throwing an error to the console. + if (!(e instanceof ReferenceError)) { + console.error(e); + } + } }); diff --git a/app/models/neighbourhood.rb b/app/models/neighbourhood.rb index cacf065ea..48a4a1cd3 100644 --- a/app/models/neighbourhood.rb +++ b/app/models/neighbourhood.rb @@ -19,6 +19,8 @@ class Neighbourhood < ApplicationRecord length: { is: 9 }, allow_blank: true + before_update :inject_parent_name_field + def shortname if name_abbr.present? name_abbr @@ -29,13 +31,21 @@ def shortname end end + def contextual_name + # "Wardname, Countryname (Region)" + return "#{shortname}, #{parent_name} (#{unit.titleize})" if parent_name + + # "Wardname (Region)" + "#{shortname} (#{unit.titleize})" + end + def fullname if name.present? - name + name elsif name_abbr.present? name_abbr else - "[not set]" + '[not set]' end end @@ -67,4 +77,11 @@ def find_from_postcodesio_response(res) unit_name: res['admin_ward']) end end + + private + + def inject_parent_name_field + self.parent_name = parent.name if parent + true + end end diff --git a/app/models/sites_neighbourhood.rb b/app/models/sites_neighbourhood.rb index 7656ca50f..1c5d5e4c7 100644 --- a/app/models/sites_neighbourhood.rb +++ b/app/models/sites_neighbourhood.rb @@ -9,4 +9,8 @@ class SitesNeighbourhood < ApplicationRecord scope: :site_id, message: 'Neighbourhood cannot be assigned more than once to a site' } + + def name + neighbourhood.to_s + end end diff --git a/app/views/admin/sites/_form.html.erb b/app/views/admin/sites/_form.html.erb index 5ddc68352..15013901d 100644 --- a/app/views/admin/sites/_form.html.erb +++ b/app/views/admin/sites/_form.html.erb @@ -49,38 +49,38 @@

Who took this photo?

Main neighbourhood

+

This neighbourhood will be listed in the main PlaceCal directory. It cannot be changed after the site is created.

- <%= f.fields_for :sites_neighbourhood do |sn| %> + <%= f.simple_fields_for :sites_neighbourhood do |sn| %> <% if @primary_neighbourhood_id %> -

<%= @all_neighbourhoods.find(@primary_neighbourhood_id).name %>

+

<%= @all_neighbourhoods.find(@primary_neighbourhood_id).contextual_name %>

+ <%= sn.hidden_field :relation_type, value: "Primary" %> + <%= sn.hidden_field :neighbourhood_id, value: @primary_neighbourhood_id %> <% else %> <%= sn.hidden_field :relation_type, value: "Primary" %> - <%= sn.select :neighbourhood_id, options_from_collection_for_select(@all_neighbourhoods, 'id', 'name', @primary_neighbourhood_id), class: 'form-control', include_blank: true %> + <%= sn.input :neighbourhood_id, collection: options_for_sites_neighbourhoods, include_blank: false, + value_method: ->(obj) { obj[:id] }, label_method: ->(obj) { obj[:name] }, + input_html: { class: 'form-control select2 col-6' }, + label: '', label_html: { hidden: true } %> <% end %> <% end %> +

Other neighbourhoods to include

+

Information from these neighbourhoods will also be displayed on this site

-
- <% @all_neighbourhoods.each do |neighbourhood| %> - <%= fields_for "site[sites_neighbourhoods_attributes][#{neighbourhood.id}]" do |sna|%> -
- <% end %> +
+ <%= f.simple_fields_for :sites_neighbourhoods do |neighbourhood| %> + <%= render 'sites_neighbourhood_fields', :f => neighbourhood %> <% end %> + +

- <%= f.button :submit, class: "btn btn-primary " %> + <%= f.button :submit, class: "btn btn-primary btn-lg" %> <% unless @site.new_record? %> - <%= link_to "Destroy Site", admin_site_path(@site), method: :delete, class: "btn btn-danger" %> + <%= link_to "Destroy Site", admin_site_path(@site), method: :delete, class: "btn btn-danger btn-lg" %> <% end %> <% end %> diff --git a/app/views/admin/sites/_sites_neighbourhood_fields.html.erb b/app/views/admin/sites/_sites_neighbourhood_fields.html.erb new file mode 100644 index 000000000..d3b79e481 --- /dev/null +++ b/app/views/admin/sites/_sites_neighbourhood_fields.html.erb @@ -0,0 +1,16 @@ +
+ <%# The style width setting here is applied to dynamically created elements, we do not know why. %> + <%# TODO: Fix the dynamic styling so that width does not get applied, so we can remove this smell %> + <%= f.input :neighbourhood_id, collection: options_for_sites_neighbourhoods, include_blank: false, + value_method: ->(obj) { obj[:id] }, + label_method: ->(obj) { obj[:name] }, + input_html: { class: 'form-control select2', style: "width: 599.8px;" }, + label: '', label_html: { hidden: true } %> + + <%# This label causes behaviours.site.js to remove the association from the form %> + <%= f.label :ignore, class: 'cocoon_delete-this' if f.object.relation_type == 'Primary' %> +
+ <%= f.hidden_field :relation_type, value: 'Secondary' %> + <%= link_to_remove_association 'Remove', f, class: "pl-2 pt-1 text-danger" %> +
+
diff --git a/db/migrate/20220125175817_add_parent_name_field_to_neighbourhoods.rb b/db/migrate/20220125175817_add_parent_name_field_to_neighbourhoods.rb new file mode 100644 index 000000000..5cfbde6f1 --- /dev/null +++ b/db/migrate/20220125175817_add_parent_name_field_to_neighbourhoods.rb @@ -0,0 +1,7 @@ +class AddParentNameFieldToNeighbourhoods < ActiveRecord::Migration[6.1] + def change + add_column :neighbourhoods, :parent_name, :string + + Neighbourhood.find_each(&:save) + end +end diff --git a/db/schema.rb b/db/schema.rb index d65e98be1..7e45750cc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_01_24_170103) do +ActiveRecord::Schema.define(version: 2022_01_25_175817) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -125,6 +125,7 @@ t.string "unit_code_key", default: "WD19CD" t.string "unit_code_value" t.string "unit_name" + t.string "parent_name" t.index ["ancestry"], name: "index_neighbourhoods_on_ancestry" end diff --git a/package.json b/package.json index fd5a88700..0c9b62746 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "yarn": ">= 1.21.1" }, "dependencies": { + "@nathanvda/cocoon": "^1.2.14", "@rails/ujs": "^6.0.2", "@rails/webpacker": "5.4.3", "axios": "^0.24.0", diff --git a/test/integration/admin/sites_integration_test.rb b/test/integration/admin/sites_integration_test.rb index 92b12ca36..ae8065310 100644 --- a/test/integration/admin/sites_integration_test.rb +++ b/test/integration/admin/sites_integration_test.rb @@ -35,10 +35,17 @@ class AdminSitesIntegrationTest < ActionDispatch::IntegrationTest assert_select 'label', 'Hero image' assert_select 'label', 'Hero image credit' - # See all neighbourhoods - assert_select '.site__neighbourhoods' do - assert_select 'label', @number_of_neighbourhoods - end + # See just neighbourhoods they admin + # In short: + # - Find the cocoon template for the Secondary Neighbourhoods