- ><%= _('This section\'s answers are common to all datasets') %> -
- <% end %> -- <% end %> - <% end %> -
diff --git a/app/assets/stylesheets/dmpopidor.scss b/app/assets/stylesheets/dmpopidor.scss index ffbedca..3fb3f34 100644 --- a/app/assets/stylesheets/dmpopidor.scss +++ b/app/assets/stylesheets/dmpopidor.scss @@ -669,7 +669,7 @@ } /* - Datasets + Research Outputs */ .nav-tabs { li.disabled { @@ -680,21 +680,21 @@ } } -.datasets-description { +.research-outputs-description { width: 50vw; padding: 0 5px; margin-top: 5px; - .dataset-element { + .research-output-element { display: flex; flex-direction: row; - .dataset-name { + .research-output-name { width: 30%; } - .dataset-description { + .research-output-description { width: 60%; } - .dataset-actions { + .research-output-actions { width: 10%; display: flex; align-items: center; diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index a66ef44..a2c5f4a 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -135,7 +135,7 @@ def permitted_params permitted = params.require(:answer).permit(:id, :text, :plan_id, :user_id, :question_id, :lock_version, - :dataset_id, :is_common, + :research_output_id, :is_common, question_option_ids: []) # If question_option_ids has been filtered out because it was a # scalar value (e.g. radiobutton answer) diff --git a/app/controllers/datasets_controller.rb b/app/controllers/datasets_controller.rb deleted file mode 100644 index 9d6bcd4..0000000 --- a/app/controllers/datasets_controller.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -class DatasetsController < ApplicationController - - after_action :verify_authorized - - # GET /plans/:plan_id/datasets - def index - begin - @plan = Plan.find(params[:plan_id]) - @datasets = @plan.datasets - - authorize @plan - render('plans/datasets', locals: { plan: @plan, datasets: @datasets }) - rescue ActiveRecord::RecordNotFound - flash[:alert] = _("There is no plan associated with id %{id}") % { - id: params[:id] - } - redirect_to(:controller => 'plans', :action => 'index') - end - end - - def destroy - @plan = Plan.find(params[:plan_id]) - @dataset = Dataset.find(params[:id]) - authorize @plan - if @dataset.destroy - flash[:notice] = success_message(@plan, _("deleted")) - redirect_to(:action => 'index') - else - flash[:alert] = failure_message(@plan, _("delete")) - redirect_to(:action => 'index') - end - end - - - -end diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index ab67067..287a1a0 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -152,7 +152,7 @@ def note_params params.require(:note) .permit(:text, :archived_by, :user_id, :answer_id, :plan_id, - :question_id, :dataset_id) + :question_id, :research_output_id) end end diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 274563e..d61c936 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -150,7 +150,7 @@ ).find(params[:id]) authorize @plan - @datasets = @plan.datasets.order(:order) + @research_outputs = @plan.research_outputs.order(:order) @visibility = if @plan.visibility.present? @plan.visibility.to_s @@ -400,7 +400,7 @@ :principal_investigator_phone, :principal_investigator, :principal_investigator_email, :data_contact, :principal_investigator_identifier, :data_contact_email, - :data_contact_phone, :guidance_group_ids, datasets_attributes: %i[id name description order _destroy]) + :data_contact_phone, :guidance_group_ids, research_outputs_attributes: %i[id name description order _destroy]) end # different versions of the same template have the same family_id @@ -457,7 +457,7 @@ readonly = !plan.editable_by?(current_user.id) # Since the answers have been pre-fetched through plan (see Plan.load_for_phase) # we create a hash whose keys are question id and value is the answer associated - answers = plan.answers.reduce({}) { |m, a| m["#{a.question_id}_#{a.dataset_id}"] = a; m } + answers = plan.answers.reduce({}) { |m, a| m["#{a.question_id}_#{a.research_output_id}"] = a; m } render("/phases/edit", locals: { base_template_org: phase.template.base_org, plan: plan, diff --git a/app/controllers/research_outputs_controller.rb b/app/controllers/research_outputs_controller.rb new file mode 100644 index 0000000..5ed2c20 --- /dev/null +++ b/app/controllers/research_outputs_controller.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class ResearchOutputsController < ApplicationController + + after_action :verify_authorized + + # GET /plans/:plan_id/research_outputs + def index + begin + @plan = Plan.find(params[:plan_id]) + @research_outputs = @plan.research_outputs + + authorize @plan + render('plans/research_outputs', locals: { plan: @plan, research_outputs: @research_outputs }) + rescue ActiveRecord::RecordNotFound + flash[:alert] = _("There is no plan associated with id %{id}") % { + id: params[:id] + } + redirect_to(:controller => 'plans', :action => 'index') + end + end + + def destroy + @plan = Plan.find(params[:plan_id]) + @research_output = ResearchOutput.find(params[:id]) + authorize @plan + if @research_output.destroy + flash[:notice] = success_message(@plan, _("deleted")) + redirect_to(:action => 'index') + else + flash[:alert] = failure_message(@plan, _("delete")) + redirect_to(:action => 'index') + end + end + + + +end diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 6624b5b..2d17974 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -33,10 +33,10 @@ import '../views/orgs/admin_edit'; import '../views/orgs/shibboleth_ds'; import '../views/plans/download'; -import '../views/plans/datasets'; import '../views/plans/edit_details'; import '../views/plans/index'; import '../views/plans/new'; +import '../views/plans/research_outputs'; import '../views/plans/share'; import '../views/public_templates/show'; import '../views/roles/edit'; diff --git a/app/javascript/views/answers/edit.js b/app/javascript/views/answers/edit.js index c2d6c47..2ca15a1 100644 --- a/app/javascript/views/answers/edit.js +++ b/app/javascript/views/answers/edit.js @@ -37,22 +37,22 @@ if (isObject(data.question)) { // Object related to question within data received if (isNumber(data.question.id)) { if (isString(data.question.answer_status)) { - $(`#answer-status-${data.question.id}-dataset-${data.dataset.id}`).html(data.question.answer_status); + $(`#answer-status-${data.question.id}-research-output-${data.research_output.id}`).html(data.question.answer_status); TimeagoFactory.render($('time.timeago')); } if (isString(data.question.locking)) { // When an answer is stale... // Removes event handlers for the saved form detachEventHandlers(form); // eslint-disable-line no-use-before-define // Reflesh form view with the new partial form received - $(`#answer-form-${data.question.id}-dataset-${data.dataset.id}`).html(data.question.form); + $(`#answer-form-${data.question.id}-research-output-${data.research_output.id}`).html(data.question.form); // Retrieves the newly form added to the DOM - const newForm = $(`#answer-form-${data.question.id}-dataset-${data.dataset.id}`).find('form'); + const newForm = $(`#answer-form-${data.question.id}-research-output-${data.research_output.id}`).find('form'); // Attaches event handlers for the new form attachEventHandlers(newForm); // eslint-disable-line no-use-before-define // Refresh optimistic locking view with the form that caused the locking - $(`#answer-locking-${data.question.id}-dataset-${data.dataset.id}`).html(data.question.locking); + $(`#answer-locking-${data.question.id}-research-output-${data.research_output.id}`).html(data.question.locking); } else { // When answer is NOT stale... - $(`#answer-locking-${data.question.id}-dataset-${data.dataset.id}`).html(''); + $(`#answer-locking-${data.question.id}-research-output-${data.research_output.id}`).html(''); if (isNumber(data.question.answer_lock_version)) { form.find('#answer_lock_version').val(data.question.answer_lock_version); } @@ -198,12 +198,12 @@ $('.is_common_cb').click((e) => { const target = $(e.currentTarget); const targetState = target.prop('checked'); - const parentTab = target.parents('.main_dataset'); + const parentTab = target.parents('.main_research_output'); const sectionContent = target.parents('.section-content'); // Set answers 'is_common' hidden checkbox to the same state // as the master checkbox - // Used to indicate that answers from the first dataset are common to all + // Used to indicate that answers from the first research output are common to all parentTab.find('.ans_is_common').each((i, el) => { $(el).prop('checked', targetState); }); @@ -215,13 +215,13 @@ } }); - // Enable or disable datasets tabs depending on 'is_common' state + // Enable or disable research outputs tabs depending on 'is_common' state if (targetState) { - sectionContent.find('.datasets_tabs').each((i, el) => { + sectionContent.find('.research_outputs_tabs').each((i, el) => { $(el).addClass('disabled'); }); } else { - sectionContent.find('.datasets_tabs').each((i, el) => { + sectionContent.find('.research_outputs_tabs').each((i, el) => { $(el).removeClass('disabled'); }); } diff --git a/app/javascript/views/notes/index.js b/app/javascript/views/notes/index.js index badfca7..25348eb 100644 --- a/app/javascript/views/notes/index.js +++ b/app/javascript/views/notes/index.js @@ -31,8 +31,8 @@ && isObject(data.title) && isString(data.title.id) && isString(data.title.html)) { - $(`#notes-${data.notes.id}-dataset-${data.dataset.id}`).html(data.notes.html); - $(`#notes-title-${data.title.id}-dataset-${data.dataset.id}`).html(data.title.html); + $(`#notes-${data.notes.id}-research-output-${data.research_output.id}`).html(data.notes.html); + $(`#notes-title-${data.title.id}-research-output-${data.research_output.id}`).html(data.title.html); } clean(); // eslint-disable-line no-use-before-define initOrReload(); // eslint-disable-line no-use-before-define diff --git a/app/javascript/views/plans/datasets.js b/app/javascript/views/plans/datasets.js deleted file mode 100644 index 5a9ffab..0000000 --- a/app/javascript/views/plans/datasets.js +++ /dev/null @@ -1,36 +0,0 @@ - -$(() => { - $('#datasets').sortable({ - handle: '.dataset-actions .handle', - stop: () => { - $('#datasets .dataset-element').each(function callback(index) { - $(this).find('.dataset-order').val(index + 1); - }); - }, - }); - - $('#add-dataset').click(() => { - const lastDataset = $('#datasets .dataset-element').last(); - const lastDatasetOrder = parseInt(lastDataset.find('.dataset-order').val(), 10); - const duplicated = lastDataset.clone(false, false); - const duplicatedId = `plan_datasets_attributes_${new Date().getTime()}`; - const duplicatedName = `plan[datasets_attributes][${new Date().getTime()}]`; - - // Dataset name - duplicated.find('.dataset-name input').attr('id', `${duplicatedId}_name`); - duplicated.find('.dataset-name input').attr('name', `${duplicatedName}[name]`); - duplicated.find('.dataset-name label').attr('for', `${duplicatedId}_name`); - duplicated.find('.dataset-name input').val(null); - // Dataset description - duplicated.find('.dataset-description input').attr('id', `${duplicatedId}_description`); - duplicated.find('.dataset-description input').attr('name', `${duplicatedName}[description]`); - duplicated.find('.dataset-description label').attr('for', `${duplicatedId}_description`); - duplicated.find('.dataset-description input').val(null); - // Dataset order - duplicated.find('.dataset-order').attr('id', `${duplicatedId}_order`); - duplicated.find('.dataset-order').attr('name', `${duplicatedName}[order]`); - duplicated.find('.dataset-order').val(lastDatasetOrder + 1); - - duplicated.appendTo('#datasets'); - }); -}); diff --git a/app/javascript/views/plans/download.js b/app/javascript/views/plans/download.js index e629812..a1b0b2d 100644 --- a/app/javascript/views/plans/download.js +++ b/app/javascript/views/plans/download.js @@ -28,14 +28,14 @@ } }); - $('#select-all-datasets').on('click', (e) => { + $('#select-all-research-outputs').on('click', (e) => { if (e.target.checked) { // Iterate each checkbox - $('.dataset-checkbox').each(function check() { + $('.research-output-checkbox').each(function check() { this.checked = true; }); } else { - $('.dataset-checkbox').each(function check() { + $('.research-output-checkbox').each(function check() { this.checked = false; }); } diff --git a/app/javascript/views/plans/research_outputs.js b/app/javascript/views/plans/research_outputs.js new file mode 100644 index 0000000..a3db2f0 --- /dev/null +++ b/app/javascript/views/plans/research_outputs.js @@ -0,0 +1,36 @@ + +$(() => { + $('#research-outputs').sortable({ + handle: '.research-output-actions .handle', + stop: () => { + $('#research-outputs .research-output-element').each(function callback(index) { + $(this).find('.research-output-order').val(index + 1); + }); + }, + }); + + $('#add-research-output').click(() => { + const lastResearchOutput = $('#research-outputs .research-output-element').last(); + const lastResearchOutputOrder = parseInt(lastResearchOutput.find('.research-output-order').val(), 10); + const duplicated = lastResearchOutput.clone(false, false); + const duplicatedId = `plan_research_outputs_attributes_${new Date().getTime()}`; + const duplicatedName = `plan[research_outputs_attributes][${new Date().getTime()}]`; + + // Research Output name + duplicated.find('.research-output-name input').attr('id', `${duplicatedId}_name`); + duplicated.find('.research-output-name input').attr('name', `${duplicatedName}[name]`); + duplicated.find('.research-output-name label').attr('for', `${duplicatedId}_name`); + duplicated.find('.research-output-name input').val(null); + // Research Output description + duplicated.find('.research-output-description input').attr('id', `${duplicatedId}_description`); + duplicated.find('.research-output-description input').attr('name', `${duplicatedName}[description]`); + duplicated.find('.research-output-description label').attr('for', `${duplicatedId}_description`); + duplicated.find('.research-output-description input').val(null); + // Research Output order + duplicated.find('.research-output-order').attr('id', `${duplicatedId}_order`); + duplicated.find('.research-output-order').attr('name', `${duplicatedName}[order]`); + duplicated.find('.research-output-order').val(lastResearchOutputOrder + 1); + + duplicated.appendTo('#research-outputs'); + }); +}); diff --git a/app/models/answer.rb b/app/models/answer.rb index 15e7ef7..b963cd5 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -3,29 +3,29 @@ # # Table name: answers # -# id :integer not null, primary key -# is_common :boolean default(FALSE) -# lock_version :integer default(0) -# text :text -# created_at :datetime -# updated_at :datetime -# dataset_id :integer -# plan_id :integer -# question_id :integer -# user_id :integer +# id :integer not null, primary key +# is_common :boolean default(FALSE) +# lock_version :integer default(0) +# text :text +# created_at :datetime +# updated_at :datetime +# plan_id :integer +# question_id :integer +# research_output_id :integer +# user_id :integer # # Indexes # -# answers_plan_id_idx (plan_id) -# answers_question_id_idx (question_id) -# answers_user_id_idx (user_id) -# index_answers_on_dataset_id (dataset_id) +# answers_plan_id_idx (plan_id) +# answers_question_id_idx (question_id) +# answers_user_id_idx (user_id) +# index_answers_on_research_output_id (research_output_id) # # Foreign Keys # -# fk_rails_... (dataset_id => datasets.id) # fk_rails_... (plan_id => plans.id) # fk_rails_... (question_id => questions.id) +# fk_rails_... (research_output_id => research_outputs.id) # fk_rails_... (user_id => users.id) # @@ -44,7 +44,7 @@ belongs_to :plan - belongs_to :dataset + belongs_to :research_output has_many :notes, dependent: :destroy diff --git a/app/models/concerns/exportable_plan.rb b/app/models/concerns/exportable_plan.rb index 0f10c0b..8001a14 100644 --- a/app/models/concerns/exportable_plan.rb +++ b/app/models/concerns/exportable_plan.rb @@ -55,7 +55,7 @@ hash[:customization] = template.customization_of.present? hash[:title] = self.title hash[:answers] = self.answers - hash[:datasets] = self.datasets + hash[:research_outputs] = self.research_outputs # add the relevant questions/answers phases = [] diff --git a/app/models/dataset.rb b/app/models/dataset.rb deleted file mode 100644 index 33316ea..0000000 --- a/app/models/dataset.rb +++ /dev/null @@ -1,55 +0,0 @@ -# == Schema Information -# -# Table name: datasets -# -# id :integer not null, primary key -# description :text -# is_default :boolean default(FALSE) -# name :string -# order :integer -# created_at :datetime not null -# updated_at :datetime not null -# plan_id :integer -# -# Indexes -# -# index_datasets_on_plan_id (plan_id) -# -# Foreign Keys -# -# fk_rails_... (plan_id => plans.id) -# - -class Dataset < ActiveRecord::Base - belongs_to :plan - has_many :answers, dependent: :destroy - - default_scope { order(order: :asc) } - - def main? - eql?(plan.datasets.where(order: 1).first) - end - - # Return main dataset - def get_main - plan.datasets.first - end - - def has_common_answers?(section_id) - self.answers.each do |answer| - if answer.question_id.in?(Section.find(section_id).questions.pluck(:id)) && answer.is_common - return true - end - end - return false - end - - ## - # deep copy the given dataset - # - # Returns Dataset - def self.deep_copy(dataset) - dataset.dup - end - - end diff --git a/app/models/plan.rb b/app/models/plan.rb index d02f552..f224511 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -106,21 +106,21 @@ has_many :roles - # DATASETS - has_many :datasets, dependent: :destroy, inverse_of: :plan do - # Returns the default dataset + # RESEARCH OUTPUTS + has_many :research_outputs, dependent: :destroy, inverse_of: :plan do + # Returns the default research output def default find_by(is_default: true) end - # Toggles the default dataset between default and normal + # Toggles the default research output between default and normal # Uses the 'is_default' flag: - # - Removes it if there are more than one dataset - # - Adds it back is there's only one dataset left + # - Removes it if there are more than one research output + # - Adds it back is there's only one research output left def toggle_default if count > 1 unless default.nil? - default.update(name: 'Default dataset') if default.name.nil? + default.update(name: 'Default research output') if default.name.nil? default.update(is_default: false) end else @@ -139,7 +139,7 @@ accepts_nested_attributes_for :roles - accepts_nested_attributes_for :datasets, reject_if: :all_blank, allow_destroy: true + accepts_nested_attributes_for :research_outputs, reject_if: :all_blank, allow_destroy: true # =============== # = Validations = @@ -232,20 +232,20 @@ # # Returns Plan # CHANGES - # Added Dataset Support + # Added Research Output Support def self.deep_copy(plan) plan_copy = plan.dup plan_copy.title = "Copy of " + plan.title plan_copy.save! - plan.datasets.each do |dataset| - dataset_copy = Dataset.deep_copy(dataset) - dataset_copy.plan_id = plan_copy.id - dataset_copy.save! + plan.research_outputs.each do |research_output| + research_output_copy = ResearchOutput.deep_copy(research_output) + research_output_copy.plan_id = plan_copy.id + research_output_copy.save! - dataset.answers.each do |answer| + research_output.answers.each do |answer| answer_copy = Answer.deep_copy(answer) answer_copy.plan_id = plan_copy.id - answer_copy.dataset_id = dataset_copy.id + answer_copy.research_output_id = research_output_copy.id answer_copy.save! end diff --git a/app/models/research_output.rb b/app/models/research_output.rb new file mode 100644 index 0000000..a7dec1f --- /dev/null +++ b/app/models/research_output.rb @@ -0,0 +1,55 @@ +# == Schema Information +# +# Table name: research_outputs +# +# id :integer not null, primary key +# description :text +# is_default :boolean default(FALSE) +# name :string +# order :integer +# created_at :datetime not null +# updated_at :datetime not null +# plan_id :integer +# +# Indexes +# +# index_research_output_on_plan_id (plan_id) +# +# Foreign Keys +# +# fk_rails_... (plan_id => plans.id) +# + +class ResearchOutput < ActiveRecord::Base + belongs_to :plan + has_many :answers, dependent: :destroy + + default_scope { order(order: :asc) } + + def main? + eql?(plan.research_outputs.where(order: 1).first) + end + + # Return main research output + def get_main + plan.research_outputs.first + end + + def has_common_answers?(section_id) + self.answers.each do |answer| + if answer.question_id.in?(Section.find(section_id).questions.pluck(:id)) && answer.is_common + return true + end + end + return false + end + + ## + # deep copy the given research output + # + # Returns Research output + def self.deep_copy(research_output) + research_output.dup + end + + end diff --git a/app/models/settings/template.rb b/app/models/settings/template.rb index d80c5c0..6bef9a9 100644 --- a/app/models/settings/template.rb +++ b/app/models/settings/template.rb @@ -1,20 +1,20 @@ -# == Schema Information -# -# Table name: settings -# -# id :integer not null, primary key -# target_type :string not null -# value :text -# var :string not null -# created_at :datetime not null -# updated_at :datetime not null -# target_id :integer not null -# -# Indexes -# -# settings_target_type_target_id_var_key (target_type,target_id,var) UNIQUE -# - +# == Schema Information +# +# Table name: settings +# +# id :integer not null, primary key +# target_type :string not null +# value :text +# var :string not null +# created_at :datetime not null +# updated_at :datetime not null +# target_id :integer not null +# +# Indexes +# +# settings_target_type_target_id_var_key (target_type,target_id,var) UNIQUE +# + module Settings class Template < RailsSettings::SettingObject diff --git a/app/views/branded/answers/_locking.html.erb b/app/views/branded/answers/_locking.html.erb index 193c2ed..0279a99 100644 --- a/app/views/branded/answers/_locking.html.erb +++ b/app/views/branded/answers/_locking.html.erb @@ -1,6 +1,6 @@
<%= _('The following answer cannot be saved') %>
<%# We do not need to re-show example answers in this lock conflict section so leave template nil %> - <%= render partial: '/answers/new_edit', locals: { template: nil, question: question, answer: answer, dataset: dataset, readonly: true, locking: true } %> + <%= render partial: '/answers/new_edit', locals: { template: nil, question: question, answer: answer, research_output: research_output, readonly: true, locking: true } %><%= _('since %{name} saved the answer below while you were editing. Please, combine your changes and then save the answer again.') % { name: user.name} %>
- ><%= _('This section\'s answers are common to all datasets') %> -
- <% end %> -+ ><%= _('This section\'s answers are common to all research outputs') %> +
+ <% end %> +