diff --git a/.eslintrc.json b/.eslintrc.json index a1e1fa6..6422e97 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -31,6 +31,12 @@ "semi": [ "error", "always" - ] + ], + "prefer-destructuring": ["error", { + "array": false, + "object": false + }, { + "enforceForRenamedProperties": false + }] } } \ No newline at end of file diff --git a/app/controllers/research_projects_controller.rb b/app/controllers/research_projects_controller.rb new file mode 100644 index 0000000..d917ca8 --- /dev/null +++ b/app/controllers/research_projects_controller.rb @@ -0,0 +1,30 @@ +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]) } + logger.debug("Returning #{@results.count} results") + 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 diff --git a/app/javascript/views/plans/edit_details.js b/app/javascript/views/plans/edit_details.js index b62bb57..be132cb 100644 --- a/app/javascript/views/plans/edit_details.js +++ b/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'); @@ -53,6 +57,48 @@ toggleCheckboxes(selections); }; + const grantNumberInfo = (grantId) => { + return `Grant number: ${grantId}`; + } + + 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(function() { + 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(''); + } + }); + } + }; + + const setInitialGrantProjectName = () => { + const grantId = grantIdHidden.val(); + const researchProject = researchProjects.find(datum => datum.grant_id === grantId); + if (researchProject) { + grantIdField.val(researchProject.description); + } + }; + $('#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 @@ -70,9 +116,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(); }); diff --git a/app/models/research_project.rb b/app/models/research_project.rb new file mode 100644 index 0000000..66ebda1 --- /dev/null +++ b/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 diff --git a/app/views/plans/_edit_details.html.erb b/app/views/plans/_edit_details.html.erb index 38143d4..0475ecc 100644 --- a/app/views/plans/_edit_details.html.erb +++ b/app/views/plans/_edit_details.html.erb @@ -30,11 +30,16 @@
- <%= f.label(:grant_number, _('Grant number'), class: 'control-label') %> + <%= label_tag(:plan_grant_number_name, _('Grant number'), class: 'control-label') %>
+
- <%= 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) %> + Grant number: <%= @plan.grant_number %>
diff --git a/config/environments/development.rb b/config/environments/development.rb index 5584fd4..434970b 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -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 diff --git a/config/routes.rb b/config/routes.rb index d28e94a..956b9a5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/lib/open_aire_request.rb b/lib/open_aire_request.rb new file mode 100644 index 0000000..5cefeab --- /dev/null +++ b/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 diff --git a/package.json b/package.json index 57a50e3..e9e1f1c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/yarn.lock b/yarn.lock index 6b214cc..e96e129 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1276,6 +1276,11 @@ 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"