From d18a54c87433b91455e3dab51a8b8c48261e079b Mon Sep 17 00:00:00 2001 From: aignatov-bio <47317017+aignatov-bio@users.noreply.github.com> Date: Tue, 20 Apr 2021 13:35:40 +0200 Subject: [PATCH] Update create and update action for reports controller [SCI-5641] (#3260) Update create and update action [SCI-5641] --- app/assets/javascripts/reports/new.js | 70 ++++++-- .../reports/checkbox_input_component.html.erb | 2 +- .../reports/date_input_component.html.erb | 2 +- .../large_text_input_component.html.erb | 2 +- .../multi_checkbox_input_component.html.erb | 2 +- .../team_member_input_component.html.erb | 2 +- .../reports/text_input_component.html.erb | 2 +- app/controllers/reports_controller.rb | 65 ++++---- app/models/report.rb | 44 +---- app/services/report_actions/report_content.rb | 157 ++++++++++++++++++ .../_my_module_activity_element.html.erb | 3 +- .../_my_module_repository_element.html.erb | 3 +- .../elements/_step_comments_element.html.erb | 3 +- app/views/reports/new.html.erb | 4 +- .../reports/wizard/_second_step.html.erb | 2 +- config/routes.rb | 2 +- 16 files changed, 253 insertions(+), 112 deletions(-) create mode 100644 app/services/report_actions/report_content.rb diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js index b02ac0364..63dc46a60 100644 --- a/app/assets/javascripts/reports/new.js +++ b/app/assets/javascripts/reports/new.js @@ -972,8 +972,11 @@ function reportHandsonTableConverter() { var reportData = {}; // Report name - reportData.name = $('.report-name').val(); - + reportData.report = { + name: $('.report-name').val(), + description: $('#projectDescription').val(), + settings: { task: { protocol: {} } } + }; // Project reportData.project_id = dropdownSelector.getValues('#projectSelector'); @@ -983,19 +986,30 @@ function reportHandsonTableConverter() { // Template values reportData.template_values = {}; $.each($('.report-template-values-container').find('.sci-input-field, select'), function(i, field) { - reportData.template_values[field.name] = field.value; + if (field.value.length === 0) return; + + reportData.template_values[field.name] = { + value: field.value, + view_component: field.dataset.type + }; }); $.each($('.report-template-values-container .sci-checkbox'), function(i, checkbox) { if (checkbox.name.includes('[]')) { let name = checkbox.name.replace('[]', ''); if (!reportData.template_values[name]) { - reportData.template_values[name] = {}; + reportData.template_values[name] = { + value: {}, + view_component: checkbox.dataset.type + }; } reportData - .template_values[name][checkbox.value] = checkbox.checked; + .template_values[name].value[checkbox.value] = checkbox.checked; } else { - reportData.template_values[checkbox.name] = checkbox.checked; + reportData.template_values[checkbox.name] = { + value: checkbox.checked, + view_component: checkbox.dataset.type + }; } }); @@ -1003,8 +1017,8 @@ function reportHandsonTableConverter() { reportData.project_content = []; $.each($('.project-contents-container .experiment-element'), function(i, experiment) { let experimentHash = {}; - - if (!$(experiment).find('.report-experiment-checkbox').prop('checked')) return; + let expCheckbox = $(experiment).find('.report-experiment-checkbox'); + if (!expCheckbox.prop('checked') && !expCheckbox.prop('indeterminate')) return; experimentHash.experiment_id = $(experiment).find('.report-experiment-checkbox').val(); experimentHash.my_modules = []; @@ -1015,15 +1029,21 @@ function reportHandsonTableConverter() { }); // Settings - reportData.settings = { task: { protocol: {} } }; - reportData.settings.all_tasks = $('.task-contents-container .select-all-task-contents').prop('checked'); + if ($('.project-contents-container .select-all-my-modules-checkbox').prop('checked')) { + reportData.report.settings.all_tasks = $('.project-contents-container .select-all-my-modules-checkbox') + .prop('checked'); + } $.each($('.task-contents-container .content-element .protocol-setting'), function(i, e) { - reportData.settings.task.protocol[e.value] = e.checked; + if (e.checked) { + reportData.report.settings.task.protocol[e.value] = e.checked; + } }); $.each($('.task-contents-container .content-element .task-setting'), function(i, e) { - reportData.settings.task[e.value] = e.checked; + if (e.checked) { + reportData.report.settings.task[e.value] = e.checked; + } }); - reportData.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder'); + reportData.report.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder'); return reportData; } @@ -1034,6 +1054,25 @@ function reportHandsonTableConverter() { // TODO }); }); + + $('.reports-new').on('click', '#saveAsNewReport', function(e) { + var params = getReportData(); + params.report.name = 'New ' + params.report.name; + e.preventDefault(); + $.post(this.dataset.createUrl, params, function() { + // TODO + }); + }); + + + $('.reports-new').on('click', '#UpdateReport', function(e) { + e.preventDefault(); + $.ajax({ + type: 'PUT', + url: this.dataset.updateUrl, + data: getReportData() + }); + }); } function initReportWizard() { @@ -1070,8 +1109,8 @@ function reportHandsonTableConverter() { $('.reports-new-body [href="#new-report-step-2"]').on('show.bs.tab', function() { var projectContents = $('#new-report-step-2').find('.project-contents'); - if (projectContents.is(':empty')) { - let projectId = dropdownSelector.getValues('#projectSelector'); + var projectId = dropdownSelector.getValues('#projectSelector'); + if (projectContents.data('project-id') !== parseInt(projectId, 10)) { animateSpinner('.reports-new-body'); $.get(projectContents.data('project-content-url'), { project_id: projectId }, function(data) { animateSpinner('.reports-new-body', false); @@ -1169,7 +1208,6 @@ function reportHandsonTableConverter() { noEmptyOption: true, selectAppearance: 'simple', onChange: function() { - $('#new-report-step-2 .project-contents').empty(); $('.continue-button').attr('disabled', false); } }); diff --git a/app/components/reports/checkbox_input_component.html.erb b/app/components/reports/checkbox_input_component.html.erb index d52de0c6b..b25d5f36b 100644 --- a/app/components/reports/checkbox_input_component.html.erb +++ b/app/components/reports/checkbox_input_component.html.erb @@ -1,6 +1,6 @@
- <%= check_box_tag @name, true, false, class: 'sci-checkbox' %> + <%= check_box_tag @name, true, (@value == 'true'), class: 'sci-checkbox', data: { type: 'CheckboxInputComponent' } %>
<%= @label %> diff --git a/app/components/reports/date_input_component.html.erb b/app/components/reports/date_input_component.html.erb index 1c0fd5c28..ba9fd8ad5 100644 --- a/app/components/reports/date_input_component.html.erb +++ b/app/components/reports/date_input_component.html.erb @@ -1,7 +1,7 @@ <% if @editing %>
<%= label_tag @name, @label %> - <%= date_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field' %> + <%= date_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field', data: { type: 'DateInputComponent' } %>
<% else %> <%= @value %> diff --git a/app/components/reports/large_text_input_component.html.erb b/app/components/reports/large_text_input_component.html.erb index 7d2d5a063..820dc5b60 100644 --- a/app/components/reports/large_text_input_component.html.erb +++ b/app/components/reports/large_text_input_component.html.erb @@ -1,7 +1,7 @@ <% if @editing %>
<%= label_tag @name, @label %> - <%= text_area_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field' %> + <%= text_area_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field', data: { type: 'LargeTextInputComponent' } %>
<% else %> <%= @value %> diff --git a/app/components/reports/multi_checkbox_input_component.html.erb b/app/components/reports/multi_checkbox_input_component.html.erb index 01ba36d2b..98ff08ff9 100644 --- a/app/components/reports/multi_checkbox_input_component.html.erb +++ b/app/components/reports/multi_checkbox_input_component.html.erb @@ -4,7 +4,7 @@ <% @items.each do |key, value| %>
  • - <%= check_box_tag "#{@name}[]", key, false ,class: 'sci-checkbox' %> + <%= check_box_tag "#{@name}[]", key, (@value && @value[key.to_s] == 'true') ,class: 'sci-checkbox', data: { type: 'MultiCheckboxInputComponent' } %>
    <%= value %> diff --git a/app/components/reports/team_member_input_component.html.erb b/app/components/reports/team_member_input_component.html.erb index 8f2476d2f..4ef7722d7 100644 --- a/app/components/reports/team_member_input_component.html.erb +++ b/app/components/reports/team_member_input_component.html.erb @@ -1,7 +1,7 @@ <% if @editing %>
    <%= label_tag @name, @label %> - <%= select_tag @name, options_from_collection_for_select(@team_members, :id, :name), placeholder: @placeholder, class: 'sci-input-field' %> + <%= select_tag @name, options_from_collection_for_select(@team_members, :id, :name), placeholder: @placeholder, class: 'sci-input-field', data: { type: 'TeamMemberInputComponent' } %>
    <% else %> <%= @value %> diff --git a/app/components/reports/text_input_component.html.erb b/app/components/reports/text_input_component.html.erb index 4d7cb2390..eb5dbecb9 100644 --- a/app/components/reports/text_input_component.html.erb +++ b/app/components/reports/text_input_component.html.erb @@ -1,7 +1,7 @@ <% if @editing %>
    <%= label_tag @name, @label %> - <%= text_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field input-large' %> + <%= text_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field input-large', data: { type: 'TextInputComponent' } %>
    <% else %> <%= @value %> diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index d118e2b61..4ddb66816 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -1,6 +1,7 @@ class ReportsController < ApplicationController include TeamsHelper include ReportActions + include ReportsHelper BEFORE_ACTION_METHODS = %i( create @@ -29,6 +30,8 @@ class ReportsController < ApplicationController before_action :check_manage_permissions, only: BEFORE_ACTION_METHODS before_action :switch_team_with_param, only: :index + after_action :generate_pdf_report, only: %i(create update) + # Index showing all reports of a single project def index; end @@ -75,33 +78,25 @@ class ReportsController < ApplicationController # Creating new report from the _save modal of the new page def create - continue = true - begin - report_contents = JSON.parse(params.delete(:report_contents)) - rescue - continue = false - end - @report = Report.new(report_params) @report.project = @project @report.user = current_user @report.team = current_team + @report.settings = report_params[:settings] @report.last_modified_by = current_user + @report = ReportActions::ReportContent.new( + @report, + params[:project_content], + params[:template_values], + current_user + ).save_with_content - if continue && @report.save_with_contents(report_contents) + if @report log_activity(:create_report) - respond_to do |format| - format.json do - render json: { url: reports_path }, status: :ok - end - end + redirect_to reports_path else - respond_to do |format| - format.json do - render json: @report.errors, status: :unprocessable_entity - end - end + render json: @report.errors, status: :unprocessable_entity end end @@ -117,30 +112,22 @@ class ReportsController < ApplicationController # Updating existing report from the _save modal of the new page def update - continue = true - begin - report_contents = JSON.parse(params.delete(:report_contents)) - rescue - continue = false - end - @report.last_modified_by = current_user @report.assign_attributes(report_params) - if continue && @report.save_with_contents(report_contents) + @report = ReportActions::ReportContent.new( + @report, + params[:project_content], + params[:template_values], + current_user + ).save_with_content + + if @report log_activity(:edit_report) - respond_to do |format| - format.json do - render json: { url: reports_path }, status: :ok - end - end + redirect_to reports_path else - respond_to do |format| - format.json do - render json: @report.errors, status: :unprocessable_entity - end - end + render json: @report.errors, status: :unprocessable_entity end end @@ -531,7 +518,7 @@ class ReportsController < ApplicationController def report_params params.require(:report) - .permit(:name, :description, :grouped_by, :report_contents) + .permit(:name, :description, :grouped_by, :report_contents, settings: {}) end def search_params @@ -551,4 +538,8 @@ class ReportsController < ApplicationController project: report.project, message_items: { report: report.id }) end + + def generate_pdf_report + Reports::PdfJob.perform_later(@report, 'template_1', current_user) if @report.persisted? + end end diff --git a/app/models/report.rb b/app/models/report.rb index eb7ce912e..c9cb67f86 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -48,7 +48,7 @@ class Report < ApplicationRecord table_results: true, text_results: true, result_comments: true, - result_order: "atoz", + result_order: 'atoz', activities: true } }.freeze @@ -91,28 +91,6 @@ class Report < ApplicationRecord report_elements.order(:position).select { |el| el.parent.blank? } end - # Save the JSON represented contents to this report - # (this action will overwrite any existing report elements) - def save_with_contents(json_contents) - begin - Report.transaction do - # First, save the report itself - save! - - # Secondly, delete existing report elements - report_elements.destroy_all - - # Lastly, iterate through contents - json_contents.each_with_index do |json_el, i| - save_json_element(json_el, i, nil) - end - end - rescue ActiveRecord::ActiveRecordError, ArgumentError - return false - end - true - end - # Clean report elements from report # the function runs before the report is edit def cleanup_report @@ -160,24 +138,4 @@ class Report < ApplicationRecord end elements end - - private - - # Recursively save a single JSON element - def save_json_element(json_element, index, parent) - el = ReportElement.new - el.position = index - el.report = self - el.parent = parent - el.type_of = json_element['type_of'] - el.sort_order = json_element['sort_order'] - el.set_element_references(json_element['id']) - el.save! - - if json_element['children'].present? - json_element['children'].each_with_index do |child, i| - save_json_element(child, i, el) - end - end - end end diff --git a/app/services/report_actions/report_content.rb b/app/services/report_actions/report_content.rb new file mode 100644 index 000000000..440a3e839 --- /dev/null +++ b/app/services/report_actions/report_content.rb @@ -0,0 +1,157 @@ +# frozen_string_literal: true + +module ReportActions + class ReportContent + include Canaid::Helpers::PermissionsHelper + + MY_MODULE_ADDONS_ELEMENTS = [] + + def initialize(report, content, template_values, user) + @content = content + @settings = report.settings + @user = user + @element_position = 0 + @report = report + @template_values = template_values + end + + def save_with_content + Report.transaction do + # Save the report itself + @report.save! + + # Delete existing report elements + @report.report_elements.destroy_all + + # Save new report elements + generate_content + + # Delete existing template values + @report.report_template_values.destroy_all + + formatted_template_values = @template_values.as_json.map { |k, v| v['name'] = k; v } + # Save new template values + @report.report_template_values.create!(formatted_template_values) + end + + @report + rescue ActiveRecord::ActiveRecordError, ArgumentError => e + Rails.logger.error e.message + raise ActiveRecord::Rollback + end + + private + + def generate_content + @content.each do |_i, exp| + generate_experiment_content(exp) + end + end + + def generate_experiment_content(exp) + experiment = Experiment.find_by(id: exp[:experiment_id]) + return if !experiment && !can_read_experiment?(experiment, @user) + + experiment_element = save_element({ 'experiment_id' => experiment.id }, :experiment, nil) + generate_my_modules_content(experiment, experiment_element, exp[:my_modules]) + end + + def generate_my_modules_content(experiment, experiment_element, selected_my_modules) + my_modules = experiment.my_modules + .active + .includes(:results, protocols: [:steps]) + .where(id: selected_my_modules) + my_modules.sort_by { |m| selected_my_modules.index m.id }.each do |my_module| + my_module_element = save_element({ 'my_module_id' => my_module.id }, :my_module, experiment_element) + + if @settings.dig('task', 'protocol', 'description') + save_element({ 'my_module_id' => my_module.id }, :my_module_protocol, my_module_element) + end + + generate_steps_content(my_module, my_module_element) + + generate_results_content(my_module, my_module_element) + + if @settings.dig('task', 'activities') + save_element({ 'my_module_id' => my_module.id }, :my_module_activity, my_module_element) + + end + + my_module.experiment.project.assigned_repositories_and_snapshots.each do |repository| + save_element( + { 'my_module_id' => my_module.id, 'repository_id' => repository.id }, + :my_module_repository, + my_module_element + ) + end + + MY_MODULE_ADDONS_ELEMENTS.each do |e| + send("generate_#{e}_content", my_module, my_module_element) + end + end + end + + def generate_steps_content(my_module, my_module_element) + my_module.protocols.first.steps + .includes(:checklists, :step_tables, :step_assets, :step_comments) + .order(:position).each do |step| + step_element = nil + if step.completed && @settings.dig('task', 'protocol', 'completed_steps') + step_element = save_element({ 'step_id' => step.id }, :step, my_module_element) + elsif @settings.dig('task', 'protocol', 'uncompleted_steps') + step_element = save_element({ 'step_id' => step.id }, :step, my_module_element) + end + + next unless step_element + + if @settings.dig('task', 'protocol', 'step_checklists') + step.checklists.each do |checklist| + save_element({ 'checklist_id' => checklist.id }, :step_checklist, step_element) + end + end + + if @settings.dig('task', 'protocol', 'step_tables') + step.step_tables.each do |table| + save_element({ 'table_id' => table.id }, :step_table, step_element) + end + end + + if @settings.dig('task', 'protocol', 'step_files') + step.step_assets.each do |asset| + save_element({ 'asset_id' => asset.id }, :step_asset, step_element) + end + end + + if @settings.dig('task', 'protocol', 'step_comments') + save_element({ 'step_id' => step.id }, :step_comments, step_element) + end + end + end + + def generate_results_content(my_module, my_module_element) + my_module.results do |result| + result_type = (result.result_asset || result.result_table || result.result_text).class.to_s.underscore + + next unless @settings.dig('task', result_type) + + result_element = save_element({ 'result_id' => result.id }, result_type, my_module_element) + + save_element({ 'result_id' => result.id }, :result_comments, result_element) + end + end + + def save_element(reference, type_of, parent) + el = ReportElement.new + el.position = @element_position + el.report = @report + el.parent = parent + el.type_of = type_of + el.set_element_references(reference) + el.save! + + @element_position += 1 + + el + end + end +end diff --git a/app/views/reports/elements/_my_module_activity_element.html.erb b/app/views/reports/elements/_my_module_activity_element.html.erb index 4208fe468..1e068c9d9 100644 --- a/app/views/reports/elements/_my_module_activity_element.html.erb +++ b/app/views/reports/elements/_my_module_activity_element.html.erb @@ -1,7 +1,6 @@ <% if my_module.blank? and @my_module.present? then my_module = @my_module end %> -<% if order.blank? and @order.present? then order = @order end %> <% timestamp = Time.current + 1.year - 2.days %> -<% activities = ActivitiesService.my_module_activities(my_module).order(created_at: order) %> +<% activities = ActivitiesService.my_module_activities(my_module).order(created_at: :desc) %>
    " data-name="<%=t "projects.reports.elements.module_activity.sidebar_name" %>" data-icon-class="fas fa-list">
    diff --git a/app/views/reports/elements/_my_module_repository_element.html.erb b/app/views/reports/elements/_my_module_repository_element.html.erb index 5e1af0083..360a57206 100644 --- a/app/views/reports/elements/_my_module_repository_element.html.erb +++ b/app/views/reports/elements/_my_module_repository_element.html.erb @@ -3,9 +3,8 @@ <% repository ||= nil %> <% repository_snapshot ||= nil %> <% repository = assigned_repository_or_snapshot(my_module, element_id, repository, repository_snapshot) %> -<% order ||= @order %> <% timestamp = Time.current + 1.year - 1.days %> -<% rows_json = my_module.repository_json_hot(repository, order) %> +<% rows_json = my_module.repository_json_hot(repository, :desc) %>
    -<% if order.blank? and @order.present? then order = @order end %> -<% comments = step.step_comments.order(created_at: order) %> +<% comments = step.step_comments.order(created_at: :desc) %> <% timestamp = Time.current + 1.year %> <% for_export_all = defined?(export_all) && export_all %>
    " data-icon-class="fas fa-comment"> diff --git a/app/views/reports/new.html.erb b/app/views/reports/new.html.erb index f27e30389..3b3f988c8 100644 --- a/app/views/reports/new.html.erb +++ b/app/views/reports/new.html.erb @@ -65,13 +65,13 @@
    -
    +
    <% if report.id %> <%= render partial: 'reports/wizard/project_contents.html.erb', locals: { project: report.project, report: report } %> diff --git a/config/routes.rb b/config/routes.rb index cd75696e8..155bc4f26 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -194,7 +194,7 @@ Rails.application.routes.draw do via: [:get, :post, :put, :patch] end - resources :reports, only: [:index, :new, :create] do + resources :reports, only: [:index, :new, :create, :update] do member do get :document_preview get :save_pdf_to_inventory_modal, defaults: { format: 'json' }