Skip to content

Commit

Permalink
Merge pull request #179 from curationexperts/collections
Browse files Browse the repository at this point in the history
Add collection selection UI to edit forms
  • Loading branch information
mark-dce authored Apr 15, 2024
2 parents f71bd85 + b302538 commit 4a6620b
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 22 deletions.
46 changes: 37 additions & 9 deletions app/assets/stylesheets/admin/items.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
.item input, .item textarea {
width: 50rem;
display: block;
}
.item {
input, textarea {
width: 50rem;
display: block;
}

select {
width: 35rem;
margin-right: 2rem;
height: 1.9rem;
}

button.delete_value {
width: 13rem;
}

button.add_value {
display: block;
margin-top: 0.25rem;
}

.item .required {
font-style: italic;
.required {
font-style: italic;
}

label {
margin-bottom: 0.5rem;
}
}

#choose_blueprint button {
display: block;
margin-bottom: 0.25rem;
#choose_blueprint {
width: fit-content;

button {
display: block;
width: 100%;
margin-bottom: 0.25rem;
}
}


4 changes: 2 additions & 2 deletions app/helpers/t3_form_builder.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Custom form controls to support T3 field-specific data types
# e.g. #vacabulary provides a customized select populated with a defined vocabulary
class T3FormBuilder < ActionView::Helpers::FormBuilder
def vocabulary(method, options = {})
def vocabulary_field(method, options = {})
multiple = options.delete(:multiple)
selected = options.delete(:value) || ''
select_options = options.except(:multiple)
.reverse_merge(
{ name: @template.field_name(@object_name, method, multiple: multiple) }
)
.merge({ selected: selected })
option_tags = @template.options_from_collection_for_select(Collection.order(:created_at), :id, :id, selected)
option_tags = @template.options_from_collection_for_select(Collection.order(:created_at), :label, :label, selected)
select(method, option_tags, { prompt: 'Select one', selected: '', disabled: true }, select_options)
end
end
13 changes: 10 additions & 3 deletions app/models/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ class Field < ApplicationRecord
integer: 3,
float: 4,
date: 5,
boolean: 6
boolean: 6,
vocabulary: 7
}

TYPE_TO_SOLR = {
Expand All @@ -16,7 +17,8 @@ class Field < ApplicationRecord
'integer' => 'lt',
'float' => 'dbt',
'date' => 'dt',
'boolean' => 'b'
'boolean' => 'b',
'vocabulary' => 's'
}.freeze

TYPE_TO_HELPER = {
Expand All @@ -25,7 +27,8 @@ class Field < ApplicationRecord
'integer' => :number_field,
'float' => :number_field,
'date' => :date_field,
'boolean' => :check_box
'boolean' => :check_box,
'vocabulary' => :vocabulary_field
}.freeze

validates :name, presence: true
Expand Down Expand Up @@ -98,6 +101,10 @@ def move(position) # rubocop:disable Metrics/MethodLength
end
end

def form_helper
TYPE_TO_HELPER[data_type]
end

private

def clear_solr_field
Expand Down
8 changes: 8 additions & 0 deletions app/models/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ def prune_orphans(batch, previously_checked)
end
end

def label
metadata[label_field]
end

def to_partial_path
"admin/#{super}"
end
Expand Down Expand Up @@ -115,4 +119,8 @@ def required_fields_present
end
end
end

def label_field
@label_field ||= blueprint.fields.first.name
end
end
9 changes: 5 additions & 4 deletions app/views/admin/items/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= form_with(model: item, scope: 'item', id: 'item_fields', class: 'item') do |form| %>
<%= form_with(model: item, scope: 'item', id: 'item_fields', class: 'item', builder: T3FormBuilder) do |form| %>
<% if item.errors.any? %>
<div style="color: red">
<h2><%= pluralize(item.errors.count, "error") %> prohibited this item from being saved:</h2>
Expand All @@ -23,20 +23,21 @@
<label>
<%= field.name -%>
<%= content_tag(:span, '(required)', class: 'required') if field.required -%>
<br/>

<% field_method = Field::TYPE_TO_HELPER[field.data_type] %>
<% if field.multiple %>
<% item_detail.object[field.name] ||= [nil] %>
<% item_detail.object[field.name].each.with_index(1) do |value, index| %>
<%= item_detail.send(field_method, field.name,
<%= item_detail.send(field.form_helper, field.name,
value: value, id: item_detail.field_id(field.name, index),
multiple: field.multiple, aria: {label: field.name + " #{index}",
required: field.required}) %>
<%= form.button t('t3.item.delete_entry', field: field.name, index: index), name: 'refresh', value: ['delete', field.name, index], class: 'delete_value' %>
<br/>
<% end %>
<%= form.button t('t3.item.add_entry', field: field.name), name: 'refresh', value: ['add', field.name, -1], class: 'add_value' %>
<% else %>
<%= item_detail.send(field_method, field.name, multiple: field.multiple,
<%= item_detail.send(field.form_helper, field.name, multiple: field.multiple,
aria: {label: field.name, required: field.required}) %>
<% end %>
</label>
Expand Down
8 changes: 6 additions & 2 deletions spec/helpers/t3_form_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
let(:tag_options) { {} }

describe '#vocabulary' do
let(:vocabulary_helper) { Capybara.string(form_builder.vocabulary(:collection, tag_options)) }
let(:vocabulary_helper) { Capybara.string(form_builder.vocabulary_field(:collection, tag_options)) }

it 'renders a select with the expected id' do
expect(vocabulary_helper).to have_select('item[metadata][collection]')
Expand All @@ -33,7 +33,11 @@
let(:tag_options) { { value: 'Green' } }

before do
collections = [OpenStruct.new({ id: 'Red' }), OpenStruct.new({ id: 'Green' }), OpenStruct.new({ id: 'Blue' })]
collections = [
instance_double(Collection, { label: 'Red', id: 5 }),
instance_double(Collection, { label: 'Green', id: 20 }),
instance_double(Collection, { label: 'Blue', id: 25 })
]
allow(Collection).to receive(:order).and_return(collections)
end

Expand Down
9 changes: 9 additions & 0 deletions spec/models/field_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@
end
end

describe '#form_helper' do
it 'is defined for each data_type' do
described_class.data_types.each_key do |data_type|
field.data_type = data_type
expect(field.form_helper).to be_present, "Missing form_helper mapping for data_type: #{data_type}"
end
end
end

describe '#solr_suffix' do
it 'ends in "m" for multivalued fields' do
field.multiple = true
Expand Down
16 changes: 14 additions & 2 deletions spec/models/item_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
let(:new_item) { described_class.new(metadata: basic_description) }
let(:basic_description) do
{
'Title' => 'One Hundred Years of Solitute',
'Title' => 'One Hundred Years of Solitude',
'Author' => ['Márquez, Gabriel García'],
'Date' => '1967'
}
end
let(:solr_doc) do
{
'blueprint_ssi' => 'Sample Blueprint',
'title_tesi' => 'One Hundred Years of Solitute',
'title_tesi' => 'One Hundred Years of Solitude',
'author_tesim' => ['Márquez, Gabriel García'],
'date_ltsi' => '1967'
}
Expand Down Expand Up @@ -46,6 +46,18 @@
end
end

describe '#label' do
let(:blueprint) { FactoryBot.build(:blueprint, name: 'Sample Blueprint') }
let(:new_item) { described_class.new(blueprint: blueprint, metadata: basic_description.as_json) }

it 'returns the value of the bluprint title field' do
allow(blueprint).to receive(:fields).and_return(
[FactoryBot.build(:field, name: 'Title', data_type: 'text_en')]
)
expect(new_item.label).to eq 'One Hundred Years of Solitude'
end
end

describe '#to_solr' do
let(:blueprint) { FactoryBot.build(:blueprint, name: 'Sample Blueprint') }
let(:new_item) { described_class.new(blueprint: blueprint, metadata: basic_description.as_json) }
Expand Down
28 changes: 28 additions & 0 deletions spec/views/admin/collections/edit.html.erb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,32 @@
expect(rendered).to have_button('refresh', value: 'delete keyword 2')
end
end

describe 'a vocabulary field' do
let(:vocabulary_field) do
FactoryBot.build(:field, name: 'collection', data_type: 'vocabulary', multiple: false, id: 1, sequence: 1)
end

before do
collections = [
instance_double(Collection, { id: 1, label: 'Cyan' }),
instance_double(Collection, { id: 2, label: 'Magenta' }),
instance_double(Collection, { id: 4, label: 'Yellow' })
]
allow(Collection).to receive(:order).and_return(collections)
end

it 'renders a slection list' do
allow(blueprint).to receive(:fields).and_return([vocabulary_field])
render
expect(rendered).to have_select('item[metadata][collection]')
end

it 'lists available values' do
allow(blueprint).to receive(:fields).and_return([vocabulary_field])
render
select_options = Capybara.string(rendered).all('select option').map(&:text)
expect(select_options).to include('Cyan', 'Magenta', 'Yellow')
end
end
end

0 comments on commit 4a6620b

Please sign in to comment.