Skip to content

Commit

Permalink
Merge pull request #2128 from DMPRoadmap/feature/research-grant-id
Browse files Browse the repository at this point in the history
Add typeahead field for Research Grant ID
  • Loading branch information
xsrust committed May 9, 2019
2 parents fe439be + 73b0c6e commit 1dacd38
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 8 deletions.
8 changes: 7 additions & 1 deletion .eslintrc.json
Expand Up @@ -31,6 +31,12 @@
"semi": [
"error",
"always"
]
],
"prefer-destructuring": ["error", {
"array": false,
"object": false
}, {
"enforceForRenamedProperties": false
}]
}
}
2 changes: 1 addition & 1 deletion Gemfile.lock
Expand Up @@ -52,7 +52,7 @@ GEM
io-like (~> 0.3.0)
arel (6.0.4)
ast (2.4.0)
autoprefixer-rails (9.5.1)
autoprefixer-rails (9.5.1.1)
execjs
bcrypt (3.1.12)
better_errors (2.5.1)
Expand Down
29 changes: 29 additions & 0 deletions app/controllers/research_projects_controller.rb
@@ -0,0 +1,29 @@
class ResearchProjectsController < ApplicationController


DEFAULT_FUNDER_TYPE = "H2020"

def index
render json: research_projects
end

def search
@results = research_projects.select { |r| r.description.match(params[:description]) }
render json: @results
end

private

def research_projects
@research_projects ||= begin
Rails.cache.fetch(["research_projects", funder_type], expires_in: 1.day) do
Thread.new { OpenAireRequest.new(funder_type).get!.results }.value
end
end
end

def funder_type
params.fetch(:type, DEFAULT_FUNDER_TYPE)
end

end
46 changes: 46 additions & 0 deletions app/javascript/views/plans/edit_details.js
@@ -1,7 +1,11 @@
import { Tinymce } from '../../utils/tinymce';
import getConstant from '../../constants';
import 'bootstrap-3-typeahead';

$(() => {
const grantIdField = $('.grant-id-typeahead');
const grantIdHidden = $('input#plan_grant_number');

Tinymce.init();
$('#is_test').click((e) => {
$('#plan_visibility').val($(e.target).is(':checked') ? 'is_test' : 'privately_visible');
Expand Down Expand Up @@ -53,6 +57,45 @@ $(() => {
toggleCheckboxes(selections);
};

const grantNumberInfo = grantId => `Grant number: ${grantId}`;

const setInitialGrantProjectName = () => {
const grantId = grantIdHidden.val();
const researchProjects = window.researchProjects;
const researchProject = researchProjects.find(datum => datum.grant_id === grantId);
if (researchProject) {
grantIdField.val(researchProject.description);
}
};

const setUpTypeahead = () => {
if ($('.edit_plan').length) {
$.get('/research_projects.json', (data) => {
window.researchProjects = data;
const descriptionData = $.map(data, datum => datum.description);
grantIdField.typeahead({ source: descriptionData });
}).then(() => { setInitialGrantProjectName(); });
grantIdField.on('change', () => {
const current = grantIdField.typeahead('getActive');
if (current) {
// match or partial match found
const currentResearchProject = window.researchProjects.find((datum) => {
const fixString = string => String(string).toLowerCase();
return fixString(datum.description) === fixString(current);
});
if (currentResearchProject) {
const grantId = currentResearchProject.grant_id;
$('#grant_number_info').html(grantNumberInfo(grantId));
grantIdHidden.val(grantId);
}
} else {
$('#grant_number_info').html(grantNumberInfo(''));
grantIdHidden.val('');
}
});
}
};

$('#other-guidance-orgs').find('input[type="checkbox"]').click((e) => {
const checkbox = $(e.target);
// Since this is the modal window, copy any selections over to the priority list
Expand All @@ -70,9 +113,12 @@ $(() => {
}
syncGuidance(checkbox.closest('ul[id]'));
});

$('#priority-guidance-orgs').find('input[type="checkbox"]').click((e) => {
syncGuidance($(e.target).closest('ul[id]'));
});

toggleCheckboxes($('#priority-guidance-orgs input[type="checkbox"]:checked').map((i, el) => $(el).val()).get());

setUpTypeahead();
});
13 changes: 13 additions & 0 deletions app/models/research_project.rb
@@ -0,0 +1,13 @@
# frozen_string_literal

class ResearchProject < Struct.new(:grant_id, :description)

def to_json(val = nil)
{ grant_id: grant_id, description: description }.to_json
end

def id
object_id
end

end
11 changes: 8 additions & 3 deletions app/views/plans/_edit_details.html.erb
Expand Up @@ -30,11 +30,16 @@
</div>
<div class="form-group"><!-- grant_number -->
<div class="col-md-12">
<%= f.label(:grant_number, _('Grant number'), class: 'control-label') %>
<%= label_tag(:plan_grant_number_name, _('Grant number'), class: 'control-label') %>
</div>

<div class="col-md-8">
<%= f.text_field(:grant_number, class: "form-control", "aria-required": false, 'data-toggle': 'tooltip',
title: _('Grant reference number if applicable [POST-AWARD DMPs ONLY]')) %>
<%= text_field_tag(:plan_grant_number_name, '',
class: "grant-id-typeahead form-control",
autocomplete: "off",
aria: { required: false }) %>
<%= f.hidden_field(:grant_number) %>
<span class="text-muted" id="grant_number_info">Grant number: <%= @plan.grant_number %></span>
</div>
</div>
<div class="form-group"><!-- description -->
Expand Down
6 changes: 5 additions & 1 deletion config/environments/development.rb
Expand Up @@ -13,7 +13,11 @@

# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
if File.exist?(Rails.root.join('tmp', 'caching-dev.txt'))
config.action_controller.perform_caching = true
else
config.action_controller.perform_caching = false
end

# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
Expand Down
11 changes: 11 additions & 0 deletions config/routes.rb
Expand Up @@ -256,4 +256,15 @@
resources :users, only: [:edit, :update]
resources :notifications, except: [:show]
end

get "research_projects/search", action: "search",
controller: "research_projects",
constraints: { format: "json" }

get "research_projects/(:type)", action: "index",
controller: "research_projects",
constraints: { format: "json" }



end
33 changes: 33 additions & 0 deletions lib/open_aire_request.rb
@@ -0,0 +1,33 @@
# frozen_string_literal

require "open-uri"
require "nokogiri"

class OpenAireRequest

API_URL = "https://api.openaire.eu/projects/dspace/%s/ALL/ALL"

attr_reader :funder_type

def initialize(funder_type)
@funder_type = funder_type
end

def get!
Rails.logger.info("Fetching fresh data from #{API_URL % funder_type}")
data = open(API_URL % funder_type)
Rails.logger.info("Fetched fresh data from #{API_URL % funder_type}")
@results = Nokogiri::XML(data).xpath("//pair/displayed-value").map do |node|
parts = node.content.split("-")
grant_id = parts.shift.to_s.strip
description = parts.join(" - ").strip
ResearchProject.new(grant_id, description)
end
return self
end

def results
Array(@results)
end

end
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -26,6 +26,7 @@
"dependencies": {
"@rails/webpacker": "3.5",
"bootstrap": "^4.1.3",
"bootstrap-3-typeahead": "^4.0.2",
"bootstrap-sass": "^3.3.7",
"chart.js": "^2.7.2",
"eslint": "^5.8.0",
Expand Down
19 changes: 17 additions & 2 deletions spec/features/plans_spec.rb
Expand Up @@ -11,6 +11,21 @@
@template = create(:template, org: @org)
@user = create(:user, org: @org)
sign_in(@user)

OpenURI.expects(:open_uri).returns(<<~XML
<form-value-pairs>
<value-pairs value-pairs-name="H2020projects" dc-term="relation">
<pair>
<displayed-value>
115797 - INNODIA - Translational approaches to disease modifying therapy of type 1 diabetes: an innovative approach towards understanding and arresting type 1 diabetes – Sofia ref.: 115797
</displayed-value>
<stored-value>info:eu-repo/grantAgreement/EC/H2020/115797/EU</stored-value>
</pair>
</value-pairs>
</form-value-pairs>
XML
)

end

scenario "User creates a new Plan", :js do
Expand All @@ -36,7 +51,7 @@
expect(page).to have_css("input[type=text][value='#{@plan.title}']")

within "#edit_plan_#{@plan.id}" do
fill_in "Grant number", with: "1234"
fill_in "Grant number", with: "Innodia"
fill_in "Project abstract", with: "Plan abstract..."
fill_in "ID", with: "ABCDEF"
fill_in "ORCID iD", with: "My ORCID"
Expand All @@ -50,7 +65,7 @@
expect(current_path).to eql(overview_plan_path(@plan))
expect(@plan.title).to eql("My test plan")
expect(@plan.funder_name).to eql(@funding_org.name)
expect(@plan.grant_number).to eql("1234")
expect(@plan.grant_number).to eql("115797")
expect(@plan.description).to eql("Plan abstract...")
expect(@plan.identifier).to eql("ABCDEF")
name = [@user.firstname, @user.surname].join(" ")
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Expand Up @@ -1276,6 +1276,11 @@ bonjour@^3.5.0:
multicast-dns "^6.0.1"
multicast-dns-service-types "^1.1.0"

bootstrap-3-typeahead@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/bootstrap-3-typeahead/-/bootstrap-3-typeahead-4.0.2.tgz#cb1c969044856862096fc8c71cc21b3acbb50412"
integrity sha1-yxyWkESFaGIJb8jHHMIbOsu1BBI=

bootstrap-sass@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/bootstrap-sass/-/bootstrap-sass-3.3.7.tgz#6596c7ab40f6637393323ab0bc80d064fc630498"
Expand Down

0 comments on commit 1dacd38

Please sign in to comment.