Skip to content

Commit

Permalink
Add project dataset select format
Browse files Browse the repository at this point in the history
Allow project owners to add questions with a pre set list of options
which can be selected when extracting information from requests.

There are also options to allow blank value or multiple values, these
effect how the form select input is rendered in the extracting sidebar.

Fixes #8117
  • Loading branch information
gbp committed Oct 11, 2024
1 parent 898e19b commit e6fccc2
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 6 deletions.
6 changes: 5 additions & 1 deletion app/controllers/alaveteli_pro/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,11 @@ def project_params
when 'edit_key_set', 'update_key_set'
params.fetch(:project, {}).permit(
key_set_attributes: [
:id, keys_attributes: %i[id title format order _destroy]
:id, keys_attributes: [
:id, :title, :format, :order, :_destroy, options: [
:select_allow_blank, :select_allow_muliple, { select_options: [] }
]
]
]
)
when 'edit_contributors', 'update_contributors'
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/projects/extracts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def find_info_request

def extract_params
params.require(:extract).permit(
:dataset_key_set_id, values_attributes: [:dataset_key_id, :value]
:dataset_key_set_id, values_attributes: [:dataset_key_id, :value, value: []]

Check warning on line 74 in app/controllers/projects/extracts_controller.rb

View workflow job for this annotation

GitHub Actions / build

[rubocop] reported by reviewdog 🐶 Line is too long. [82/80] (https://rubystyle.guide#max-line-length) Raw Output: app/controllers/projects/extracts_controller.rb:74:81: C: Layout/LineLength: Line is too long. [82/80] (https://rubystyle.guide#max-line-length)
)
end

Expand Down
24 changes: 24 additions & 0 deletions app/javascript/controllers/projects/key_set/select_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Controller } from "@hotwired/stimulus";
import { streamUpdate } from "helpers/stream_update";

export default class extends Controller {
static targets = ["newInput"];
static values = { name: String };

addOption(event) {
event.preventDefault();

const newValue = this.newInputTarget.value;
if (!newValue) return;

const form = this.element.closest("form");
streamUpdate(form, { [this.nameValue]: newValue });
}

removeOption(event) {
event.preventDefault();

const li = event.target.closest("li");
if (li) li.remove();
}
}
16 changes: 15 additions & 1 deletion app/models/dataset/key.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# == Schema Information
# Schema version: 20210114161442
# Schema version: 20240926164308
#
# Table name: dataset_keys
#
Expand All @@ -10,6 +10,7 @@
# order :integer
# created_at :datetime not null
# updated_at :datetime not null
# options :jsonb
#

##
Expand All @@ -24,6 +25,7 @@ class Dataset::Key < ApplicationRecord

FORMATS = {
text: { title: _('Text'), regexp: /\A.*\z/m },
select: { title: _('Select'), regexp: /\A.*\z/m },
numeric: { title: _('Numeric'), regexp: /\A[0-9,%\+\-\s]*\z/ },
boolean: { title: _('Yes/No'), regexp: /\A(0|1)\z/ }
}.freeze
Expand All @@ -40,4 +42,16 @@ def self.format_options
def format_regexp
FORMATS[format.to_sym][:regexp]
end

def select_options
options.fetch('select_options', [])
end

def select_allow_blank?
options.fetch('select_allow_blank', '0').to_i == 1
end

def select_allow_muliple?
options.fetch('select_allow_muliple', '0').to_i == 1
end
end
9 changes: 9 additions & 0 deletions app/models/dataset/value.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ def title
key.title
end

def value=(new_value)
case key.format
when 'select'
super(Array(new_value).reject(&:blank?).join(', '))
else
super
end
end

def mapped_value
case key.format
when 'boolean'
Expand Down
5 changes: 5 additions & 0 deletions app/views/alaveteli_pro/projects/_key_set.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
data: { action: 'change->projects--key-set#updateKey' },
autocomplete: 'off' %>
</div>

<% if lookup_context.exists?("alaveteli_pro/projects/_#{key.format}_key") %>
<%= render partial: "alaveteli_pro/projects/#{key.format}_key",
locals: { form: f, key: key } %>
<% end %>
</div>

<div class="project-key-set__key__remove-question">
Expand Down
41 changes: 41 additions & 0 deletions app/views/alaveteli_pro/projects/_select_key.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<%= form.fields_for :options, key.options do |f| %>
<div class="project-key-set__key__value">
<%= f.label :select_allow_blank do %>
<%= f.check_box :select_allow_blank, checked: key.select_allow_blank?, autocomplete: 'off' %>
<%= _('Allow blank') %>
<% end %>
</div>

<div class="project-key-set__key__value">
<%= f.label :select_allow_muliple do %>
<%= f.check_box :select_allow_muliple, checked: key.select_allow_muliple?, autocomplete: 'off' %>
<%= _('Allow muliple') %>
<% end %>
</div>

<%= content_tag(:div, class: "project-key-set__key__value", data: {
controller: "projects--key-set--select",
projects__key_set__select_name_value: "#{f.object_name}[select_options][]"
}) do %>
<%= f.label :select_options, _('Options') %>
<ul>
<% key.select_options.each_with_index do |option, index| %>
<li>
<%= option %>
<%= hidden_field_tag "#{f.object_name}[select_options][]", option %>
<%= button_tag class: 'button-unstyled', data: { action: 'click->projects--key-set--select#removeOption' } do %>
<%= _('Remove') %>
<% end %>
</li>
<% end %>
</ul>
<div class="row collapse postfix-radius">
<div class="small-10 columns">
<%= text_field_tag "select_option", nil, data: { projects__key_set__select_target: 'newInput' } %>
</div>
<div class="small-2 columns">
<%= button_tag _('Add'), class: 'button-tertiary postfix', data: { action: 'click->projects--key-set--select#addOption' } %>
</div>
</div>
<% end %>
<% end %>
4 changes: 4 additions & 0 deletions app/views/projects/dataset/keys/_select_key.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="dataset-key">
<%= f.label :value, key.title %>
<%= f.select :value, key.select_options, { include_blank: key.select_allow_blank? }, multiple: key.select_allow_muliple? %>
</div>
5 changes: 5 additions & 0 deletions db/migrate/20240926164308_add_options_to_dataset_key.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddOptionsToDatasetKey < ActiveRecord::Migration[7.0]
def change
add_column :dataset_keys, :options, :jsonb, default: {}
end
end
1 change: 1 addition & 0 deletions doc/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Highlighted Features

* Add project dataset question "select" format (Graeme Porteous)
* Fix script/mailin when multiple EXCEPTION_NOTIFICATIONS_TO addresses are
specified (Graeme Porteous)
* Add example logrotate configuration (Graeme Porteous)
Expand Down
7 changes: 6 additions & 1 deletion spec/factories/dataset_keys.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# == Schema Information
# Schema version: 20210114161442
# Schema version: 20240926164308
#
# Table name: dataset_keys
#
Expand All @@ -10,6 +10,7 @@
# order :integer
# created_at :datetime not null
# updated_at :datetime not null
# options :jsonb
#

FactoryBot.define do
Expand All @@ -24,6 +25,10 @@
format { 'text' }
end

trait :select do
format { 'select' }
end

trait :numeric do
format { 'numeric' }
end
Expand Down
13 changes: 11 additions & 2 deletions spec/models/dataset/key_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# == Schema Information
# Schema version: 20210114161442
# Schema version: 20240926164308
#
# Table name: dataset_keys
#
Expand All @@ -10,6 +10,7 @@
# order :integer
# created_at :datetime not null
# updated_at :datetime not null
# options :jsonb
#

require 'spec_helper'
Expand Down Expand Up @@ -63,6 +64,8 @@
is_expected.not_to be_valid
key.format = 'text'
is_expected.to be_valid
key.format = 'select'
is_expected.to be_valid
key.format = 'numeric'
is_expected.to be_valid
key.format = 'boolean'
Expand All @@ -75,7 +78,8 @@

it 'returns title/format key hash' do
is_expected.to eq(
{ 'Text' => :text, 'Numeric' => :numeric, 'Yes/No' => :boolean }
{ 'Text' => :text, 'Select' => :select, 'Numeric' => :numeric,
'Yes/No' => :boolean }
)
end
end
Expand All @@ -88,6 +92,11 @@
it { is_expected.to eq described_class::FORMATS[:text][:regexp] }
end

context 'select format' do
let(:key) { FactoryBot.build(:dataset_key, :select) }
it { is_expected.to eq described_class::FORMATS[:select][:regexp] }
end

context 'numeric format' do
let(:key) { FactoryBot.build(:dataset_key, :numeric) }
it { is_expected.to eq described_class::FORMATS[:numeric][:regexp] }
Expand Down
41 changes: 41 additions & 0 deletions spec/models/dataset/value_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,45 @@ def invalid(value_to_test)
end
end
end

describe 'value=' do
context 'when format is a select' do
before do
value.key = FactoryBot.build(:dataset_key, :select)
end

it 'accept an array' do
value.value = %w[a b]
expect(value.value).to eq('a, b')
end

it 'ignores empty array values' do
value.value = %w[a] + [nil] + %w[c]
expect(value.value).to eq('a, c')
end

it 'accepts as string' do
value.value = 'a'
expect(value.value).to eq('a')
end
end
end

describe 'mapped_value' do
context 'when format is a boolean' do
before do
value.key = FactoryBot.build(:dataset_key, :boolean)
end

it 'returns No for value 0' do
value.value = 0
expect(value.mapped_value).to eq('No')
end

it 'returns Yes for value 1' do
value.value = 1
expect(value.mapped_value).to eq('Yes')
end
end
end
end

0 comments on commit e6fccc2

Please sign in to comment.