From 452547564e0c610642ba8c37a691e7e8f4ef3490 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Tue, 30 Jul 2024 10:41:06 +0200
Subject: [PATCH 01/96] Enable protocol template renaming [SCI-10851]
---
app/controllers/protocols_controller.rb | 1 -
app/models/protocol.rb | 8 --------
config/locales/en.yml | 1 -
3 files changed, 10 deletions(-)
diff --git a/app/controllers/protocols_controller.rb b/app/controllers/protocols_controller.rb
index b0ade7fb4..63a782d59 100644
--- a/app/controllers/protocols_controller.rb
+++ b/app/controllers/protocols_controller.rb
@@ -909,7 +909,6 @@ class ProtocolsController < ApplicationController
end
def set_inline_name_editing
- return unless @protocol.initial_draft?
return unless can_manage_protocol_draft_in_repository?(@protocol)
@inline_editable_title_config = {
diff --git a/app/models/protocol.rb b/app/models/protocol.rb
index a1a69b3d8..f26da6f07 100644
--- a/app/models/protocol.rb
+++ b/app/models/protocol.rb
@@ -70,12 +70,10 @@ class Protocol < ApplicationRecord
with_options if: :in_repository_published_version? do
validates :parent, presence: true
validate :parent_type_constraint
- validate :versions_same_name_constraint
end
with_options if: :in_repository_draft? do
# Only one draft can exist for each protocol
validate :ensure_single_draft
- validate :versions_same_name_constraint
end
with_options if: -> { in_repository? && !parent && !archived_changed?(from: false) } do |protocol|
# Active protocol must have unique name inside its team
@@ -797,12 +795,6 @@ class Protocol < ApplicationRecord
end
end
- def versions_same_name_constraint
- if parent.present? && !parent.name.eql?(name)
- errors.add(:base, I18n.t('activerecord.errors.models.protocol.wrong_version_name'))
- end
- end
-
def version_number_constraint
if Protocol.where(protocol_type: Protocol::REPOSITORY_TYPES)
.where.not(id: id)
diff --git a/config/locales/en.yml b/config/locales/en.yml
index a6e68a6b6..9eb819df6 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -166,7 +166,6 @@ en:
protocol:
unchangable: "Published protocols can not be changed!"
wrong_parent_type: "Protocol can only be linked to published protocol!"
- wrong_version_name: "Protocol versions should have same name!"
wrong_version_number: "Protocol version number should be sequential!"
wrong_parent_draft_number: "Procol can have only 1 draft"
attributes:
From 5841fbdda13c22953818324e90e56bd90d924dd3 Mon Sep 17 00:00:00 2001
From: Anton
Date: Fri, 9 Aug 2024 12:01:05 +0200
Subject: [PATCH 02/96] Add basic support for custom templates docx [SCI-10967]
---
Gemfile | 4 +-
Gemfile.lock | 18 +-
app/assets/javascripts/reports/new.js | 79 +++++++-
.../repositories_input_component.html.erb | 11 +
.../reports/repositories_input_component.rb | 18 ++
app/controllers/reports_controller.rb | 42 +++-
app/jobs/reports/docx_job.rb | 2 +
app/services/reports/docx.rb | 18 +-
app/services/reports/docx/draw_my_module.rb | 26 +--
app/services/reports/docx/draw_results.rb | 30 +++
app/services/reports/docx/draw_step.rb | 2 +-
app/services/reports/docx/private_methods.rb | 10 -
.../reports/docx/repository_helper.rb | 4 +-
.../reports/template_values_editor.html.erb | 75 ++++---
.../docx_templates/custom_template/docx.rb | 188 ++++++++++++++++++
.../custom_template/edit.html.erb | 57 ++++++
.../docx_templates/custom_template/name.txt | 1 +
.../docx_templates/scinote_template/docx.rb | 19 ++
.../docx_templates/scinote_template/name.txt | 1 +
app/views/reports/wizard/_first_step.html.erb | 4 +-
.../_project_template_selector.html.erb | 12 ++
config/initializers/extends.rb | 1 +
config/initializers/report_templates.rb | 14 ++
config/locales/en.yml | 4 +-
config/routes.rb | 1 +
25 files changed, 553 insertions(+), 88 deletions(-)
create mode 100644 app/components/reports/repositories_input_component.html.erb
create mode 100644 app/components/reports/repositories_input_component.rb
create mode 100644 app/services/reports/docx/draw_results.rb
create mode 100644 app/views/reports/docx_templates/custom_template/docx.rb
create mode 100644 app/views/reports/docx_templates/custom_template/edit.html.erb
create mode 100644 app/views/reports/docx_templates/custom_template/name.txt
create mode 100644 app/views/reports/docx_templates/scinote_template/docx.rb
create mode 100644 app/views/reports/docx_templates/scinote_template/name.txt
diff --git a/Gemfile b/Gemfile
index 675d300cf..453dea286 100644
--- a/Gemfile
+++ b/Gemfile
@@ -47,8 +47,8 @@ gem 'aspector' # Aspect-oriented programming for Rails
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces AR
gem 'bcrypt', '~> 3.1.10'
# gem 'caracal'
-gem 'caracal',
- git: 'https://github.com/scinote-eln/caracal.git', branch: 'rubyzip2' # Build docx report
+# gem 'caracal', git: 'https://github.com/scinote-eln/caracal.git', branch: 'rubyzip2' # Build docx report
+gem 'caracal_the_curve', '~> 1.4', '>= 1.4.6'
gem 'caxlsx' # Build XLSX files
gem 'deface', '~> 1.9'
gem 'down', '~> 5.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index dc2d6db14..5a29368f2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -22,16 +22,6 @@ GIT
docile (>= 1.1.0)
rails (>= 4)
-GIT
- remote: https://github.com/scinote-eln/caracal.git
- revision: f8e4c279adfee7801eb1024e1d6a18bb06c9c76a
- branch: rubyzip2
- specs:
- caracal (1.4.1)
- nokogiri (~> 1.6)
- rubyzip (>= 2.3)
- tilt (>= 1.4)
-
GIT
remote: https://github.com/scinote-eln/img2zpl
revision: 23d61cfc3e90ac4caa62dd08546fa0d7590a5140
@@ -227,6 +217,10 @@ GEM
capybara-email (3.0.2)
capybara (>= 2.4, < 4.0)
mail
+ caracal_the_curve (1.4.6)
+ nokogiri (~> 1.6)
+ rubyzip (>= 1.1.0, < 3.0)
+ tilt (>= 1.4)
case_transform (0.2)
activesupport
caxlsx (4.0.0)
@@ -725,7 +719,7 @@ GEM
tailwindcss-rails (2.4.0-x86_64-linux)
railties (>= 6.0.0)
thor (1.3.1)
- tilt (2.2.0)
+ tilt (2.4.0)
timecop (0.9.6)
timeout (0.4.1)
turbolinks (5.2.1)
@@ -805,7 +799,7 @@ DEPENDENCIES
canaid!
capybara
capybara-email
- caracal!
+ caracal_the_curve (~> 1.4, >= 1.4.6)
caxlsx
cssbundling-rails
cucumber-rails
diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js
index a7aba901e..ad280af9f 100644
--- a/app/assets/javascripts/reports/new.js
+++ b/app/assets/javascripts/reports/new.js
@@ -1036,6 +1036,7 @@ function reportHandsonTableConverter() {
// Settings
reportData.report.settings.template = dropdownSelector.getValues('#templateSelector');
+ reportData.report.settings.docx_template = dropdownSelector.getValues('#docxTemplateSelector');
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) {
@@ -1254,7 +1255,8 @@ function reportHandsonTableConverter() {
function reCheckContinueButton() {
if (dropdownSelector.getValues('#projectSelector').length > 0
- && dropdownSelector.getValues('#templateSelector').length > 0) {
+ && dropdownSelector.getValues('#templateSelector').length > 0
+ && dropdownSelector.getValues('#docxTemplateSelector').length > 0) {
$('.continue-button').attr('disabled', false);
} else {
$('.continue-button').attr('disabled', true);
@@ -1276,9 +1278,12 @@ function reportHandsonTableConverter() {
}
if (dropdownSelector.getValues('#projectSelector').length > 0) {
dropdownSelector.enableSelector('#templateSelector');
+ dropdownSelector.enableSelector('#docxTemplateSelector');
} else {
dropdownSelector.selectValues('#templateSelector', '');
dropdownSelector.disableSelector('#templateSelector');
+ dropdownSelector.selectValues('#docxTemplateSelector', '');
+ dropdownSelector.disableSelector('#docxTemplateSelector');
}
reCheckContinueButton();
}
@@ -1292,12 +1297,12 @@ function reportHandsonTableConverter() {
disableSearch: true,
onSelect: function() {
if (dropdownSelector.getValues('#templateSelector').length === 0) {
- $('.report-template-values-container').html('').addClass('hidden');
+ $('.report-template-values-container.pdf').html('').addClass('hidden');
reCheckContinueButton();
return;
}
- let filledFieldsCount = $('.report-template-values-container')
+ let filledFieldsCount = $('.report-template-values-container.pdf')
.find('input.sci-input-field, textarea.sci-input-field').filter(function() {
return !!this.value;
}).length;
@@ -1311,9 +1316,39 @@ function reportHandsonTableConverter() {
}
});
+ dropdownSelector.init('#docxTemplateSelector', {
+ singleSelect: true,
+ closeOnSelect: true,
+ noEmptyOption: true,
+ selectAppearance: 'simple',
+ disableSearch: true,
+ onSelect: function() {
+ if (dropdownSelector.getValues('#docxTemplateSelector').length === 0) {
+ $('.report-template-values-container.docx').html('').addClass('hidden');
+ reCheckContinueButton();
+ return;
+ }
+
+ let filledFieldsCount = $('.report-template-values-container.docx')
+ .find('input.sci-input-field, textarea.sci-input-field').filter(function() {
+ return !!this.value;
+ }).length;
+
+ if (filledFieldsCount === 0) {
+ loadDocxTemplate();
+ } else {
+ $('#templateReportWarningModal').modal('show');
+ }
+ reCheckContinueButton();
+ }
+ });
+
if (dropdownSelector.getValues('#templateSelector').length > 0) {
loadTemplate();
}
+ if (dropdownSelector.getValues('#docxTemplateSelector').length > 0) {
+ loadDocxTemplate();
+ }
}
function loadTemplate() {
@@ -1325,8 +1360,38 @@ function reportHandsonTableConverter() {
$('#templateSelector').data('selected-template', template);
$.get($('#templateSelector').data('valuesEditorPath'), params, function(result) {
- $('.report-template-values-container').removeClass('hidden');
- $('.report-template-values-container').html(result.html);
+ $('.report-template-values-container.pdf').removeClass('hidden');
+ $('.report-template-values-container.pdf').html(result.html);
+
+ $('.section').each(function() {
+ var section = $(this);
+ var collapseButton = section.find('.sn-icon-down');
+ var valuesContainer = section.find('.values-container');
+
+ if (valuesContainer.children().length === 0) {
+ collapseButton.hide();
+ }
+ });
+
+ $('.report-template-value-dropdown').each(function() {
+ dropdownSelector.init($(this), {
+ noEmptyOption: true
+ });
+ });
+ });
+ }
+
+ function loadDocxTemplate() {
+ let template = $('#docxTemplateSelector').val();
+ let params = {
+ project_id: dropdownSelector.getValues('#projectSelector'),
+ template: template
+ };
+
+ $('#docxTemplateSelector').data('selected-template', template);
+ $.get($('#docxTemplateSelector').data('valuesEditorPath'), params, function(result) {
+ $('.report-template-values-container.docx').removeClass('hidden');
+ $('.report-template-values-container.docx').html(result.html);
$('.section').each(function() {
var section = $(this);
@@ -1448,7 +1513,9 @@ function reportHandsonTableConverter() {
.on('hide.bs.modal', function() {
if (!$('#templateReportWarningModal').hasClass('skip-hide-event')) {
let previousTemplate = $('#templateSelector').data('selected-template');
+ let previousDocxTemplate = $('#docxTemplateSelector').data('selected-template');
dropdownSelector.selectValues('#templateSelector', previousTemplate);
+ dropdownSelector.selectValues('#docxTemplateSelector', previousDocxTemplate);
}
$('#templateReportWarningModal').removeClass('skip-hide-event');
});
@@ -1461,7 +1528,7 @@ function reportHandsonTableConverter() {
$('#reportWizardEditWarning').modal('show');
$('.experiment-contents').sortable();
-
+
initNameContainerFocus();
initGenerateButton();
initReportWizard();
diff --git a/app/components/reports/repositories_input_component.html.erb b/app/components/reports/repositories_input_component.html.erb
new file mode 100644
index 000000000..9906b3b2c
--- /dev/null
+++ b/app/components/reports/repositories_input_component.html.erb
@@ -0,0 +1,11 @@
+<% if @editing %>
+
+ <%= label_tag @name, @label %>
+ <%= select_tag @name, options_from_collection_for_select(@repositories, :id, :name, @value), placeholder: @placeholder, class: 'sci-input-field report-template-value-dropdown', data: { type: 'RepositoriesInputComponent' }, multiple: true %>
+
+<% else %>
+ <% @project_members.where(id: @value).each do |member| %>
+ <%= member.public_send(@displayed_field) %>
+
+ <% end %>
+<% end %>
diff --git a/app/components/reports/repositories_input_component.rb b/app/components/reports/repositories_input_component.rb
new file mode 100644
index 000000000..c7909d8c7
--- /dev/null
+++ b/app/components/reports/repositories_input_component.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Reports
+ class RepositoriesInputComponent < TemplateValueComponent
+ def initialize(report:, name:, label:, placeholder: nil, editing: true, displayed_field: :name)
+ super(report: report, name: name, label: label, placeholder: placeholder, editing: editing)
+
+ live_repositories = Repository.accessible_by_teams(report.team).sort_by { |r| r.name.downcase }
+ snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
+ .where(team: report.team)
+ .where.not(original_repository: live_repositories)
+ .select('DISTINCT ON ("repositories"."parent_id") "repositories".*')
+ .sort_by { |r| r.name.downcase }
+ @repositories = live_repositories + snapshots_of_deleted
+ @displayed_field = displayed_field
+ end
+ end
+end
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index c148511f3..2e5b20a39 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -7,13 +7,13 @@ class ReportsController < ApplicationController
before_action :load_vars, only: %i(edit update document_preview generate_pdf generate_docx status
save_pdf_to_inventory_modal save_pdf_to_inventory_item)
before_action :load_vars_nested, only: %i(create edit update generate_pdf
- generate_docx new_template_values project_contents)
+ generate_docx new_template_values new_docx_template_values project_contents)
before_action :load_wizard_vars, only: %i(new edit)
before_action :load_available_repositories, only: %i(index save_pdf_to_inventory_modal available_repositories)
before_action :check_project_read_permissions, only: %i(create edit update generate_pdf
- generate_docx new_template_values project_contents)
+ generate_docx new_template_values new_docx_template_values project_contents)
before_action :check_read_permissions, except: %i(index new create edit update destroy actions_toolbar generate_pdf
- generate_docx new_template_values project_contents
+ generate_docx new_template_values project_contents new_docx_template_values
available_repositories)
before_action :check_create_permissions, only: %i(new create)
before_action :check_manage_permissions, only: %i(edit update generate_pdf generate_docx)
@@ -37,6 +37,7 @@ class ReportsController < ApplicationController
# Report grouped by modules
def new
@templates = Extends::REPORT_TEMPLATES
+ @docx_templates = Extends::DOCX_REPORT_TEMPLATES
@report = current_team.reports.new
end
@@ -73,6 +74,39 @@ class ReportsController < ApplicationController
end
end
+ def new_docx_template_values
+ if Extends::DOCX_REPORT_TEMPLATES.key?(params[:template]&.to_sym)
+ template = params[:template]
+ else
+ return render_404
+ end
+
+ report = current_team.reports.where(project: @project).find_by(id: params[:report_id])
+ if report.present?
+ return render_403 unless can_manage_report?(report)
+ else
+ return render_403 unless can_create_reports?(current_team)
+
+ report = current_team.reports.new(project: @project)
+ end
+
+ if lookup_context.any_templates?("reports/docx_templates/#{template}/edit")
+ render json: {
+ html: render_to_string(
+ template: "reports/docx_templates/#{template}/edit",
+ layout: 'reports/template_values_editor',
+ locals: { report: report },
+ formats: :html
+ )
+ }
+ else
+ render json: {
+ html: render_to_string(partial: 'reports/wizard/no_template_values',
+ formats: :html)
+ }
+ end
+ end
+
# Creating new report from the _save modal of the new page
def create
@report = Report.new(report_params)
@@ -102,6 +136,7 @@ class ReportsController < ApplicationController
def edit
@edit = true
@active_template = @report.settings[:template]
+ @active_docx_template = @report.settings[:docx_template]
@report.settings = Report::DEFAULT_SETTINGS if @report.settings.blank?
@project_contents = {
@@ -312,6 +347,7 @@ class ReportsController < ApplicationController
def load_wizard_vars
@templates = Extends::REPORT_TEMPLATES
+ @docx_templates = Extends::DOCX_REPORT_TEMPLATES
live_repositories = Repository.accessible_by_teams(current_team).sort_by { |r| r.name.downcase }
snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
.where(team: current_team)
diff --git a/app/jobs/reports/docx_job.rb b/app/jobs/reports/docx_job.rb
index 51043ff37..1165653eb 100644
--- a/app/jobs/reports/docx_job.rb
+++ b/app/jobs/reports/docx_job.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'caracal'
+
module Reports
class DocxJob < ApplicationJob
extend InputSanitizeHelper
diff --git a/app/services/reports/docx.rb b/app/services/reports/docx.rb
index 7a0251371..46445f338 100644
--- a/app/services/reports/docx.rb
+++ b/app/services/reports/docx.rb
@@ -2,6 +2,10 @@
# rubocop:disable Style/ClassAndModuleChildren
+Dir[Rails.root.join('app/views/reports/docx_templates/**/docx.rb')].each do |file|
+ require file
+end
+
class Reports::Docx
include ActionView::Helpers::TextHelper
include ActionView::Helpers::UrlHelper
@@ -26,15 +30,23 @@ class Reports::Docx
@link_style = {}
@color = {}
@scinote_url = options[:scinote_url][0..-2]
+ @template = @settings[:docx_template] || 'scinote_template'
+
+ extend "#{@template.camelize}Docx".constantize
end
def draw
initial_document_load
- @report.root_elements.each do |subject|
- public_send("draw_#{subject.type_of}", subject)
- end
+ prepare_docx
+
@docx
end
+
+ private
+
+ def get_template_value(name)
+ @report.report_template_values.find_by(name: name)&.value
+ end
end
# rubocop:enable Style/ClassAndModuleChildren
diff --git a/app/services/reports/docx/draw_my_module.rb b/app/services/reports/docx/draw_my_module.rb
index ddfefd7df..e85ccf701 100644
--- a/app/services/reports/docx/draw_my_module.rb
+++ b/app/services/reports/docx/draw_my_module.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Reports::Docx::DrawMyModule
- def draw_my_module(subject)
+ def draw_my_module(subject, without_results: false, without_repositories: false)
color = @color
link_style = @link_style
scinote_url = @scinote_url
@@ -70,30 +70,12 @@ module Reports::Docx::DrawMyModule
draw_step(step)
end
- if my_module.results.any? && (%w(file_results table_results text_results).any? { |k| @settings.dig('task', k) })
- @docx.h4 I18n.t('Results')
- order_results_for_report(my_module.results, @settings.dig('task', 'result_order')).each do |result|
- @docx.p do
- text result.name.presence || I18n.t('projects.reports.unnamed'), italic: true
- text " #{I18n.t('search.index.archived')} ", bold: true if result.archived?
- text I18n.t('projects.reports.elements.result.user_time',
- timestamp: I18n.l(result.created_at, format: :full),
- user: result.user.full_name), color: color[:gray]
- end
- draw_result_asset(result, @settings) if @settings.dig('task', 'file_results')
- result.result_orderable_elements.each do |element|
- if @settings.dig('task', 'table_results') && element.orderable_type == 'ResultTable'
- draw_result_table(element)
- elsif @settings.dig('task', 'text_results') && element.orderable_type == 'ResultText'
- draw_result_text(element)
- end
- end
- draw_result_comments(result) if @settings.dig('task', 'result_comments')
- end
- end
+ draw_results(my_module) unless without_results
@docx.p
subject.children.active.each do |child|
+ next if without_repositories && child.type_of == 'my_module_repository'
+
public_send("draw_#{child.type_of}", child)
end
diff --git a/app/services/reports/docx/draw_results.rb b/app/services/reports/docx/draw_results.rb
new file mode 100644
index 000000000..0baedb9cf
--- /dev/null
+++ b/app/services/reports/docx/draw_results.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Reports::Docx::DrawResults
+ def draw_results(my_module)
+ color = @color
+ return unless can_read_my_module?(@user, my_module)
+
+ if my_module.results.any? && (%w(file_results table_results text_results).any? { |k| @settings.dig('task', k) })
+ @docx.h4 I18n.t('Results')
+ order_results_for_report(my_module.results, @settings.dig('task', 'result_order')).each do |result|
+ @docx.p do
+ text result.name.presence || I18n.t('projects.reports.unnamed'), italic: true
+ text " #{I18n.t('search.index.archived')} ", bold: true if result.archived?
+ text I18n.t('projects.reports.elements.result.user_time',
+ timestamp: I18n.l(result.created_at, format: :full),
+ user: result.user.full_name), color: color[:gray]
+ end
+ draw_result_asset(result, @settings) if @settings.dig('task', 'file_results')
+ result.result_orderable_elements.each do |element|
+ if @settings.dig('task', 'table_results') && element.orderable_type == 'ResultTable'
+ draw_result_table(element)
+ elsif @settings.dig('task', 'text_results') && element.orderable_type == 'ResultText'
+ draw_result_text(element)
+ end
+ end
+ draw_result_comments(result) if @settings.dig('task', 'result_comments')
+ end
+ end
+ end
+end
diff --git a/app/services/reports/docx/draw_step.rb b/app/services/reports/docx/draw_step.rb
index c6cc90660..6d4e27da6 100644
--- a/app/services/reports/docx/draw_step.rb
+++ b/app/services/reports/docx/draw_step.rb
@@ -7,7 +7,7 @@ module Reports::Docx::DrawStep
user = (step.completed? && step.last_modified_by) || step.user
timestamp = step.completed ? step.completed_on : step.created_at
@docx.p
- @docx.h5(
+ @docx.h4(
"#{I18n.t('projects.reports.elements.step.step_pos', pos: step.position_plus_one)} #{step.name}"
)
@docx.p do
diff --git a/app/services/reports/docx/private_methods.rb b/app/services/reports/docx/private_methods.rb
index 8e5db9780..1136bc635 100644
--- a/app/services/reports/docx/private_methods.rb
+++ b/app/services/reports/docx/private_methods.rb
@@ -16,16 +16,6 @@ module Reports::Docx::PrivateMethods
bottom Constants::REPORT_DOCX_MARGIN_BOTTOM
end
- @docx.page_numbers true, align: :right
-
- insert_logo
-
- @docx.p do
- text I18n.t('projects.reports.new.generate_PDF.generated_on', timestamp: I18n.l(Time.zone.now, format: :full))
- end
-
- @docx.hr
-
generate_html_styles
end
diff --git a/app/services/reports/docx/repository_helper.rb b/app/services/reports/docx/repository_helper.rb
index f24065fd9..50b693891 100644
--- a/app/services/reports/docx/repository_helper.rb
+++ b/app/services/reports/docx/repository_helper.rb
@@ -4,7 +4,7 @@ module Reports::Docx::RepositoryHelper
include InputSanitizeHelper
include ActionView::Helpers::NumberHelper
- def prepare_row_columns(repository_data, my_module, repository)
+ def prepare_row_columns(repository_data, my_module = nil, repository = nil)
result = [repository_data[:headers]]
repository_data[:rows].each do |record|
row = []
@@ -16,7 +16,7 @@ module Reports::Docx::RepositoryHelper
cell_values = {}
custom_cells = record.repository_cells
custom_cells.each do |cell|
- if cell.value.instance_of? RepositoryStockValue
+ if cell.value.instance_of?(RepositoryStockValue) && my_module
if repository.is_a?(RepositorySnapshot)
consumed_stock = record.repository_stock_consumption_cell&.value&.formatted || 0
cell_values[cell.repository_column_id] = consumed_stock
diff --git a/app/views/layouts/reports/template_values_editor.html.erb b/app/views/layouts/reports/template_values_editor.html.erb
index 1f9352e83..225c32a4a 100644
--- a/app/views/layouts/reports/template_values_editor.html.erb
+++ b/app/views/layouts/reports/template_values_editor.html.erb
@@ -17,32 +17,57 @@
<%= t('projects.reports.wizard.first_step.values_editor.description') %>
-
-
-
- <%= t('projects.reports.wizard.first_step.values_editor.header') %>
-
-
-
+<%
+ toc = yield :toc
+ header = yield :header
+ cover = yield :cover
+ footer = yield :footer
+%>
-
-
-
- <%= t('projects.reports.wizard.first_step.values_editor.cover') %>
-
-
- <%= yield :cover %>
+<% if toc.present? %>
+
+
+
+ <%= t('projects.reports.wizard.first_step.values_editor.toc') %>
+
+
+ <%= toc %>
+
-
+<% end %>
-
-
-
- <%= t('projects.reports.wizard.first_step.values_editor.footer') %>
-
-
+<% end %>
+
+<% if cover.present? %>
+
+
+
+ <%= t('projects.reports.wizard.first_step.values_editor.cover') %>
+
+
+ <%= cover %>
+
+
+<% end %>
+
+<% if footer.present? %>
+
+
+
+ <%= t('projects.reports.wizard.first_step.values_editor.footer') %>
+
+
+
+<% end %>
diff --git a/app/views/reports/docx_templates/custom_template/docx.rb b/app/views/reports/docx_templates/custom_template/docx.rb
new file mode 100644
index 000000000..b2e16276a
--- /dev/null
+++ b/app/views/reports/docx_templates/custom_template/docx.rb
@@ -0,0 +1,188 @@
+# frozen_string_literal: true
+
+module CustomTemplateDocx
+ def prepare_docx
+ report_name = get_template_value('custom_docx_report_name')
+ report_number = get_template_value('custom_docx_report_number')
+
+ @project_members = @report.project&.users
+
+ report_authors = @project_members.where(id: get_template_value('custom_docx_author[]')).pluck(:full_name).join(', ')
+ report_reviewers = @project_members.where(id: get_template_value('custom_docx_reviewer[]')).pluck(:full_name).join(', ')
+ report_author_role = get_template_value('custom_docx_author_role')
+ report_reviewer_role = get_template_value('custom_docx_reviewer_role')
+
+ @docx.header do |header|
+ header.table [[report_name, 'custom report']] do
+ border_size 1
+ cell_style cols[0], width: 8000
+ cell_style cols[1], width: 2800
+ end
+ end
+
+ @docx.footer do |footer|
+ pages = Caracal::Core::Models::TableCellModel.new do
+ p do
+ field :page
+ text ' of '
+ field :numpages
+ end
+ end
+ footer.table [['Confidential', pages]] do
+ border_top do
+ size 1
+ end
+ cell_style cols[0], width: 9500
+ cell_style cols[1], width: 1000
+ end
+ end
+
+ @docx.p
+
+ logo_data = File.read(Rails.root.join('app/assets/images/scinote_logo.png'))
+
+ c1 = Caracal::Core::Models::TableCellModel.new do
+ p report_name, bold: true
+ p ''
+ end
+
+ c2 = Caracal::Core::Models::TableCellModel.new do
+ img 'logo.png' do
+ data logo_data
+ height 20
+ width 100
+ align :left
+ end
+ end
+
+ c3 = Caracal::Core::Models::TableCellModel.new do
+ p "Author: #{report_authors}"
+ p "Role: #{report_author_role}"
+ end
+
+ c4 = Caracal::Core::Models::TableCellModel.new do
+ p "Reviewer: #{report_reviewers}"
+ p "Role: #{report_reviewer_role}"
+ end
+
+ c5 = Caracal::Core::Models::TableCellModel.new do
+ p "Report number:"
+ p report_number
+ end
+
+ @docx.table [[c1, c2], [c3, c4, c5]] do
+ border_size 2
+ cell_style rows[0], width: 3500
+ cell_style rows[1], width: 3500
+ cell_style rows[0][0], colspan: 2
+ end
+
+ @docx.p
+
+ @docx.table_of_contents do |toc|
+ toc.title 'Table of Contents'
+ toc.opts 'TOC \o "1-4" \h \z \u \t "Heading 5,1"'
+ end
+
+ @docx.page
+
+ my_modules_elements = []
+ @report.root_elements.each do |subject|
+ my_modules_elements += subject.children.active if subject.type_of == 'experiment'
+ end
+
+ @my_modules = MyModule.where(id: my_modules_elements.map { |element| element.my_module.id })
+
+ @docx.h1 'Chapter 1'
+ @docx.h2 'Sub chapter 1' if get_template_value('custom_docx_sub_chapter_1')
+ @docx.h2 'Sub chapter 2' if get_template_value('custom_docx_sub_chapter_2')
+ @docx.h1 'Chapter 2'
+ if get_template_value('custom_docx_sub_chapter_3')
+ @docx.h2 'Sub chapter 3 with inventory'
+ draw_repositories(get_template_value('custom_docx_sub_chapter_3_inventories[]'))
+ end
+ if get_template_value('custom_docx_sub_chapter_4')
+ @docx.h2 'Sub chapter 4 with inventory'
+ draw_repositories(get_template_value('custom_docx_sub_chapter_4_inventories[]'))
+ end
+ @docx.h2 'Sub chapter 5' if get_template_value('custom_docx_sub_chapter_5')
+ @docx.h2 'Sub chapter 6' if get_template_value('custom_docx_sub_chapter_6')
+ @docx.h2 'Sub chapter 7' if get_template_value('custom_docx_sub_chapter_7')
+ @docx.h1 'Chapter 3'
+ if get_template_value('custom_docx_sub_chapter_8')
+ @docx.h2 'Sub chapter 8 with task'
+ my_modules_elements.each do |element|
+ draw_my_module(element, without_results: true, without_repositories: true)
+ end
+ end
+ @docx.h2 'Sub chapter 9' if get_template_value('custom_docx_sub_chapter_9')
+ @docx.h2 'Sub chapter 10' if get_template_value('custom_docx_sub_chapter_10')
+ @docx.h2 'Sub chapter 11' if get_template_value('custom_docx_sub_chapter_11')
+ if get_template_value('custom_docx_sub_chapter_12')
+ @docx.h2 'Sub chapter 12'
+ @docx.h3 'Sub sub chapter 1' if get_template_value('custom_docx_sub_sub_chapter_1')
+ @docx.h3 'Sub sub chapter 2' if get_template_value('custom_docx_sub_sub_chapter_2')
+ end
+ @docx.h1 'Chapter 4'
+ if get_template_value('custom_docx_sub_chapter_13')
+ @docx.h2 'Sub chapter 13 with results'
+ my_modules_elements.each do |element|
+ draw_results(element.my_module)
+ end
+ end
+ @docx.h2 'Sub chapter 14' if get_template_value('custom_docx_sub_chapter_14')
+ @docx.h2 'Sub chapter 15' if get_template_value('custom_docx_sub_chapter_15')
+ @docx.h2 'Sub chapter 16' if get_template_value('custom_docx_sub_chapter_16')
+ @docx.h2 'Sub chapter 17' if get_template_value('custom_docx_sub_chapter_17')
+ @docx.h1 'Chapter 5'
+ end
+
+ def repository_docx_json(repository, rows)
+ headers = [
+ I18n.t('repositories.table.id'),
+ I18n.t('repositories.table.row_name'),
+ I18n.t('repositories.table.added_on'),
+ I18n.t('repositories.table.added_by')
+ ]
+ custom_columns = []
+ return false unless repository
+
+ repository.repository_columns.order(:id).each do |column|
+ headers.push(column.name)
+ custom_columns.push(column.id)
+ end
+
+ records = repository.repository_rows.where(id: rows)
+ .select(:id, :name, :created_at, :created_by_id, :repository_id, :parent_id, :archived)
+ { headers: headers, rows: records, custom_columns: custom_columns }
+ end
+
+ def load_repositories(repositories_id)
+ live_repositories = Repository.accessible_by_teams(@report.team).where(id: repositories_id).sort_by { |r| r.name.downcase }
+ snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
+ .where(team: @report.team)
+ .where(parent_id: repositories_id)
+ .where.not(original_repository: live_repositories)
+ .select('DISTINCT ON ("repositories"."parent_id") "repositories".*')
+ .sort_by { |r| r.name.downcase }
+ live_repositories + snapshots_of_deleted
+ end
+
+ def draw_repositories(repositories_id)
+ load_repositories(repositories_id).each do |repository|
+ rows = repository.repository_rows.where(id: @my_modules.joins(:my_module_repository_rows).select(:repository_row_id)).select(:id)
+ repository_data = repository_docx_json(repository, rows)
+
+ next unless repository_data[:rows].any? && can_read_repository?(@user, repository)
+
+ table = prepare_row_columns(repository_data, nil, repository)
+
+ @docx.p
+ @docx.p repository.name, bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
+ @docx.table table, border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
+
+ @docx.p
+ @docx.p
+ end
+ end
+end
diff --git a/app/views/reports/docx_templates/custom_template/edit.html.erb b/app/views/reports/docx_templates/custom_template/edit.html.erb
new file mode 100644
index 000000000..6bef2a79e
--- /dev/null
+++ b/app/views/reports/docx_templates/custom_template/edit.html.erb
@@ -0,0 +1,57 @@
+<% content_for :toc do %>
+
Chapter 1
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_1, label: 'Sub chapter 1') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_2, label: 'Sub chapter 2') %>
+
+
Chapter 2
+
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_3, label: 'Sub chapter 3 with inventory') %>
+
+ <%= render Reports::RepositoriesInputComponent.new(report: report, name: 'custom_docx_sub_chapter_3_inventories[]', label: 'Inventories') %>
+
+
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_4, label: 'Sub chapter 4 with inventory') %>
+
+ <%= render Reports::RepositoriesInputComponent.new(report: report, name: 'custom_docx_sub_chapter_4_inventories[]', label: 'Inventories') %>
+
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_5, label: 'Sub chapter 5') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_6, label: 'Sub chapter 6') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_7, label: 'Sub chapter 7') %>
+
+
Chapter 3
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_8, label: 'Sub chapter 8 with task') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_9, label: 'Sub chapter 9') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_10, label: 'Sub chapter 10') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_11, label: 'Sub chapter 11') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_12, label: 'Sub chapter 12') %>
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_sub_chapter_1, label: 'Sub sub chapter 1') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_sub_chapter_2, label: 'Sub sub chapter 2') %>
+
+
+
Chapter 4
+
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_13, label: 'Sub chapter 13 with results') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_14, label: 'Sub chapter 14') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_15, label: 'Sub chapter 15') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_16, label: 'Sub chapter 16') %>
+ <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_17, label: 'Sub chapter 17') %>
+
+
Chapter 5
+<% end %>
+
+<% content_for :cover do %>
+ <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_report_name, label: 'Report name') %>
+ <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_report_number, label: 'Report number') %>
+
+ <%= render Reports::ProjectMembersInputComponent.new(report: report, name: 'custom_docx_author[]', label: 'Author') %>
+ <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_author_role, label: 'Author Role') %>
+
+ <%= render Reports::ProjectMembersInputComponent.new(report: report, name: 'custom_docx_reviewer[]', label: 'Reviewer') %>
+ <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_reviewer_role, label: 'Reviewer Role') %>
+<% end %>
diff --git a/app/views/reports/docx_templates/custom_template/name.txt b/app/views/reports/docx_templates/custom_template/name.txt
new file mode 100644
index 000000000..0ad39c916
--- /dev/null
+++ b/app/views/reports/docx_templates/custom_template/name.txt
@@ -0,0 +1 @@
+Custom Template
diff --git a/app/views/reports/docx_templates/scinote_template/docx.rb b/app/views/reports/docx_templates/scinote_template/docx.rb
new file mode 100644
index 000000000..5b5e05312
--- /dev/null
+++ b/app/views/reports/docx_templates/scinote_template/docx.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module ScinoteTemplateDocx
+ def prepare_docx
+ @docx.page_numbers true, align: :right
+
+ insert_logo
+
+ @docx.p do
+ text I18n.t('projects.reports.new.generate_PDF.generated_on', timestamp: I18n.l(Time.zone.now, format: :full))
+ end
+
+ @docx.hr
+
+ @report.root_elements.each do |subject|
+ public_send("draw_#{subject.type_of}", subject)
+ end
+ end
+end
diff --git a/app/views/reports/docx_templates/scinote_template/name.txt b/app/views/reports/docx_templates/scinote_template/name.txt
new file mode 100644
index 000000000..9c7a580cc
--- /dev/null
+++ b/app/views/reports/docx_templates/scinote_template/name.txt
@@ -0,0 +1 @@
+SciNote Template
diff --git a/app/views/reports/wizard/_first_step.html.erb b/app/views/reports/wizard/_first_step.html.erb
index 5d9cda6fc..1fba29ada 100644
--- a/app/views/reports/wizard/_first_step.html.erb
+++ b/app/views/reports/wizard/_first_step.html.erb
@@ -1,5 +1,7 @@
<%= render partial: 'reports/wizard/project_template_selector', locals: {report: report} %>
-
">
+
">
+
+
">
diff --git a/app/views/reports/wizard/_project_template_selector.html.erb b/app/views/reports/wizard/_project_template_selector.html.erb
index f29b6e7d6..3a7500e6a 100644
--- a/app/views/reports/wizard/_project_template_selector.html.erb
+++ b/app/views/reports/wizard/_project_template_selector.html.erb
@@ -23,6 +23,18 @@
values_editor_path: reports_new_template_values_path(report_id: report.id)
} %>
+
+ <%= label_tag :docxTemplateSelector, t('projects.reports.wizard.first_step.select_docx_template') %>
+ <%= select_tag :docxTemplateSelector,
+ options_for_select(@docx_templates.invert, @active_docx_template),
+ prompt: t('projects.reports.wizard.first_step.select_docx_template'),
+ data: {
+ disable_on_load: report.settings[:docx_template].blank? && report.new_record?,
+ placeholder: t('projects.reports.wizard.first_step.select_docx_template'),
+ selected_template: report.settings[:docx_template],
+ values_editor_path: reports_new_docx_template_values_path(report_id: report.id)
+ } %>
+
diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb
index d7ae79061..0fab450eb 100644
--- a/config/initializers/extends.rb
+++ b/config/initializers/extends.rb
@@ -542,6 +542,7 @@ class Extends
]
REPORT_TEMPLATES = {}
+ DOCX_REPORT_TEMPLATES = {}
NOTIFIABLE_ACTIVITIES = %w(
assign_user_to_project
diff --git a/config/initializers/report_templates.rb b/config/initializers/report_templates.rb
index e482295cd..0760dadda 100644
--- a/config/initializers/report_templates.rb
+++ b/config/initializers/report_templates.rb
@@ -13,3 +13,17 @@ Dir.chdir(Rails.root.join('app/views/reports/templates')) do
end
end
end
+
+Dir.chdir(Rails.root.join('app/views/reports/docx_templates')) do
+ templates = Dir.glob('*').select { |entry| File.directory?(entry) }
+ templates.each do |template|
+ next if Extends::DOCX_REPORT_TEMPLATES[template.to_sym].present?
+
+ Extends::DOCX_REPORT_TEMPLATES[template.to_sym] =
+ if File.file?("#{template}/name.txt")
+ File.open("#{template}/name.txt").read.strip
+ else
+ template
+ end
+ end
+end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 909bdfcfd..4e5d25a02 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -798,7 +798,8 @@ en:
select_project_title: "Select project and report template"
select_project_description: "You are about to create a new report. Please select a project for which you would like to create a report, and choose the report design template. Only projects with at least 1 task are displayed."
select_project: "Select a project"
- select_template: "Select your template"
+ select_template: "Select your PDF template"
+ select_docx_template: "Select your DOCX template"
report_description: "Report description (optional)"
report_description_placeholder: "In this report you can see..."
values_editor:
@@ -807,6 +808,7 @@ en:
header: "Header"
cover: "Title page"
footer: "Footer"
+ toc: "Table of contents"
no_values_title: "No additional data required"
no_values_description: "SciNote template doesn’t need any additional input for it to be successfully generated."
second_step:
diff --git a/config/routes.rb b/config/routes.rb
index 49db07eb4..fdb9be508 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -266,6 +266,7 @@ Rails.application.routes.draw do
end
get 'reports/datatable', to: 'reports#datatable'
get 'reports/new_template_values', to: 'reports#new_template_values', defaults: { format: 'json' }
+ get 'reports/new_docx_template_values', to: 'reports#new_docx_template_values', defaults: { format: 'json' }
get 'reports/available_repositories', to: 'reports#available_repositories',
defaults: { format: 'json' }
get 'available_asset_type_columns',
From b4bcd69683cc4e9f9b50c2ca1ce7f980e95d1e45 Mon Sep 17 00:00:00 2001
From: Anton
Date: Tue, 13 Aug 2024 14:14:00 +0200
Subject: [PATCH 03/96] Add exclude metadata from reports [SCI-10978]
---
app/assets/javascripts/reports/new.js | 2 ++
.../elements/_experiment_element.html.erb | 8 +++--
.../elements/_my_module_element.html.erb | 32 +++++++++++--------
.../_my_module_protocol_element.html.erb | 8 +++--
.../_my_module_result_asset_element.html.erb | 4 ++-
.../_my_module_result_table_element.html.erb | 8 +++--
.../_my_module_result_text_element.html.erb | 8 +++--
.../elements/_my_module_step_element.html.erb | 8 +++--
.../elements/_project_header_element.html.erb | 8 +++--
.../elements/_step_asset_element.html.erb | 8 +++--
.../elements/_step_checklist_element.html.erb | 8 +++--
.../elements/_step_table_element.html.erb | 8 +++--
.../elements/_step_text_element.html.erb | 8 +++--
app/views/reports/wizard/_third_step.html.erb | 10 ++++++
config/locales/en.yml | 1 +
15 files changed, 84 insertions(+), 45 deletions(-)
diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js
index ad280af9f..28e407826 100644
--- a/app/assets/javascripts/reports/new.js
+++ b/app/assets/javascripts/reports/new.js
@@ -1052,6 +1052,8 @@ function reportHandsonTableConverter() {
reportData.report.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder');
+ reportData.report.settings.exclude_metada = $('.exclude-metadata-setting')[0].checked;
+
return reportData;
}
diff --git a/app/views/reports/elements/_experiment_element.html.erb b/app/views/reports/elements/_experiment_element.html.erb
index 86804dc9a..8ef08378e 100644
--- a/app/views/reports/elements/_experiment_element.html.erb
+++ b/app/views/reports/elements/_experiment_element.html.erb
@@ -9,9 +9,11 @@
<%= t('search.index.archived') %>
<% end %>
-
- <%= t('projects.reports.elements.experiment.user_time', code: experiment.code, timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.experiment.user_time', code: experiment.code, timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
<% if experiment.description.present? %>
<%= custom_auto_link(experiment.description, team: current_team, base64_encoded_imgs: export_all) %>
<% end %>
diff --git a/app/views/reports/elements/_my_module_element.html.erb b/app/views/reports/elements/_my_module_element.html.erb
index 43d9fd665..562495418 100644
--- a/app/views/reports/elements/_my_module_element.html.erb
+++ b/app/views/reports/elements/_my_module_element.html.erb
@@ -9,9 +9,11 @@
<%= t('search.index.archived') %>
<% end %>
-
- <%= t('projects.reports.elements.module.user_time', code: my_module.code, timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.module.user_time', code: my_module.code, timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
<% if my_module.started_on.present? %>
<%= t('projects.reports.elements.module.started_on', started_on: l(my_module.started_on, format: :full)) %>
@@ -36,18 +38,20 @@
<% end %>
-
+ <% end %>
<% if my_module.description.present? %>
diff --git a/app/views/reports/elements/_my_module_protocol_element.html.erb b/app/views/reports/elements/_my_module_protocol_element.html.erb
index 9fd76c321..88755ca91 100644
--- a/app/views/reports/elements/_my_module_protocol_element.html.erb
+++ b/app/views/reports/elements/_my_module_protocol_element.html.erb
@@ -9,9 +9,11 @@
<%= t('projects.reports.elements.module.protocol.name') %>
<% end %>
-
- <%= t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code, timestamp: l(protocol.created_at, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code, timestamp: l(protocol.created_at, format: :full)) %>
+
+ <% end %>
<% if @settings.dig('task', 'protocol', 'description') && protocol.description.present? %>
<%= custom_auto_link(protocol.prepare_for_report(:description, export_all: export_all),
diff --git a/app/views/reports/elements/_my_module_result_asset_element.html.erb b/app/views/reports/elements/_my_module_result_asset_element.html.erb
index 65c9a3e43..71857134b 100644
--- a/app/views/reports/elements/_my_module_result_asset_element.html.erb
+++ b/app/views/reports/elements/_my_module_result_asset_element.html.erb
@@ -26,7 +26,9 @@
<% end %>
- <%= t("projects.reports.elements.result_asset.user_time", user: result.user.full_name, timestamp: l(timestamp, format: :full)) %>
+ <% unless @settings.dig('exclude_metadata') %>
+ <%= t("projects.reports.elements.result_asset.user_time", user: result.user.full_name, timestamp: l(timestamp, format: :full)) %>
+ <% end %>
<% if report.settings.dig(:task, :file_results_previews) && ActiveStorageFileUtil.previewable_document?(asset&.file&.blob) %>
<%= t('projects.reports.elements.result_asset.full_preview_attached') %>
<% end %>
diff --git a/app/views/reports/elements/_my_module_result_table_element.html.erb b/app/views/reports/elements/_my_module_result_table_element.html.erb
index 2464735b8..749b20985 100644
--- a/app/views/reports/elements/_my_module_result_table_element.html.erb
+++ b/app/views/reports/elements/_my_module_result_table_element.html.erb
@@ -21,9 +21,11 @@
<% end %>
<% end %>
-
- <%= t('projects.reports.elements.result_table.user_time', timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.result_table.user_time', timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
diff --git a/app/views/reports/elements/_my_module_result_text_element.html.erb b/app/views/reports/elements/_my_module_result_text_element.html.erb
index b3b96926f..d65b63a96 100644
--- a/app/views/reports/elements/_my_module_result_text_element.html.erb
+++ b/app/views/reports/elements/_my_module_result_text_element.html.erb
@@ -11,9 +11,11 @@
<% end %>
-
- <%= t("projects.reports.elements.result_text.user_time", timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t("projects.reports.elements.result_text.user_time", timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
diff --git a/app/views/reports/elements/_my_module_step_element.html.erb b/app/views/reports/elements/_my_module_step_element.html.erb
index f0b636cd2..15f6d32ea 100644
--- a/app/views/reports/elements/_my_module_step_element.html.erb
+++ b/app/views/reports/elements/_my_module_step_element.html.erb
@@ -10,9 +10,11 @@
<%= t('projects.reports.elements.step.step_pos', pos: (step.position_plus_one)) %> <%= step.name %>
<%= step_status_label(step) %>
-
- <%= t("projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t("projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
<% step.step_orderable_elements.order(:position).each do |e| %>
diff --git a/app/views/reports/elements/_project_header_element.html.erb b/app/views/reports/elements/_project_header_element.html.erb
index 54ad6a629..735afe95e 100644
--- a/app/views/reports/elements/_project_header_element.html.erb
+++ b/app/views/reports/elements/_project_header_element.html.erb
@@ -7,9 +7,11 @@
<%= t('search.index.archived') %>
<% end %>
-
- <%= t('projects.reports.elements.project_header.user_time', code: project.code, timestamp: l(project.created_at, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.project_header.user_time', code: project.code, timestamp: l(project.created_at, format: :full)) %>
+
+ <% end %>
<% if defined?(children) %>
diff --git a/app/views/reports/elements/_step_asset_element.html.erb b/app/views/reports/elements/_step_asset_element.html.erb
index 2842a7adf..75ea45762 100644
--- a/app/views/reports/elements/_step_asset_element.html.erb
+++ b/app/views/reports/elements/_step_asset_element.html.erb
@@ -18,9 +18,11 @@
<% end %>
-
- <%= t('projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
<% if asset.previewable? && !asset.list? %>
diff --git a/app/views/reports/elements/_step_checklist_element.html.erb b/app/views/reports/elements/_step_checklist_element.html.erb
index f4d625d1a..9a7917aa3 100644
--- a/app/views/reports/elements/_step_checklist_element.html.erb
+++ b/app/views/reports/elements/_step_checklist_element.html.erb
@@ -9,9 +9,11 @@
team: current_team,
base64_encoded_imgs: export_all) %>
-
- <%= t('projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t('projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
<% items.each do |item| %>
diff --git a/app/views/reports/elements/_step_table_element.html.erb b/app/views/reports/elements/_step_table_element.html.erb
index e3334f08c..1cc9c8b3c 100644
--- a/app/views/reports/elements/_step_table_element.html.erb
+++ b/app/views/reports/elements/_step_table_element.html.erb
@@ -18,9 +18,11 @@
<% end %>
<% end %>
-
- <%= t("projects.reports.elements.#{table_type}.user_time", timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t("projects.reports.elements.#{table_type}.user_time", timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
diff --git a/app/views/reports/elements/_step_text_element.html.erb b/app/views/reports/elements/_step_text_element.html.erb
index 01c274f89..9a62410c3 100644
--- a/app/views/reports/elements/_step_text_element.html.erb
+++ b/app/views/reports/elements/_step_text_element.html.erb
@@ -8,9 +8,11 @@
<% end %>
-
- <%= t("projects.reports.elements.step_text.user_time", timestamp: l(timestamp, format: :full)) %>
-
+ <% unless @settings.dig('exclude_metadata') %>
+
+ <%= t("projects.reports.elements.step_text.user_time", timestamp: l(timestamp, format: :full)) %>
+
+ <% end %>
<% if step_text.text.present? %>
diff --git a/app/views/reports/wizard/_third_step.html.erb b/app/views/reports/wizard/_third_step.html.erb
index 642eb9db5..d56af9b24 100644
--- a/app/views/reports/wizard/_third_step.html.erb
+++ b/app/views/reports/wizard/_third_step.html.erb
@@ -194,6 +194,16 @@
+
+
+
+ />
+
+
+ <%= t("projects.reports.wizard.third_step.exclude_metadata") %>
+
+
+
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 4e5d25a02..55582e52c 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -851,6 +851,7 @@ en:
results_comments: "Result comments"
additional_content: "Additional content"
task_activity: "Include task activity"
+ exclude_metadata: "Exclude metadata"
archived: "[archived]"
deleted: "[deleted]"
From 5105079f8123636f4fc06f609a1033249d569c9a Mon Sep 17 00:00:00 2001
From: Anton
Date: Wed, 14 Aug 2024 10:52:16 +0200
Subject: [PATCH 04/96] Add exclude metadata settings [SCI-10978]
---
app/assets/javascripts/reports/new.js | 2 +-
app/services/reports/docx/draw_experiment.rb | 7 +++-
app/services/reports/docx/draw_my_module.rb | 39 +++++++++++--------
.../reports/docx/draw_my_module_protocol.rb | 6 ++-
.../reports/docx/draw_project_header.rb | 10 +++--
.../reports/docx/draw_result_asset.rb | 6 ++-
.../reports/docx/draw_result_table.rb | 7 +++-
app/services/reports/docx/draw_result_text.rb | 7 +++-
app/services/reports/docx/draw_results.rb | 9 +++--
app/services/reports/docx/draw_step.rb | 13 ++++---
app/services/reports/docx/draw_step_asset.rb | 7 +++-
.../reports/docx/draw_step_checklist.rb | 7 +++-
app/services/reports/docx/draw_step_table.rb | 7 +++-
app/services/reports/docx/draw_step_text.rb | 7 +++-
.../elements/_experiment_element.html.erb | 2 +-
.../elements/_my_module_element.html.erb | 32 ++++++++-------
.../_my_module_protocol_element.html.erb | 2 +-
.../_my_module_result_asset_element.html.erb | 2 +-
.../_my_module_result_table_element.html.erb | 2 +-
.../_my_module_result_text_element.html.erb | 2 +-
.../elements/_my_module_step_element.html.erb | 2 +-
.../elements/_project_header_element.html.erb | 2 +-
.../elements/_step_asset_element.html.erb | 2 +-
.../elements/_step_checklist_element.html.erb | 2 +-
.../elements/_step_table_element.html.erb | 2 +-
.../elements/_step_text_element.html.erb | 2 +-
config/database.yml | 1 -
27 files changed, 114 insertions(+), 75 deletions(-)
diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js
index 28e407826..519bae098 100644
--- a/app/assets/javascripts/reports/new.js
+++ b/app/assets/javascripts/reports/new.js
@@ -1052,7 +1052,7 @@ function reportHandsonTableConverter() {
reportData.report.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder');
- reportData.report.settings.exclude_metada = $('.exclude-metadata-setting')[0].checked;
+ reportData.report.settings.exclude_metadata = $('.exclude-metadata-setting')[0].checked;
return reportData;
}
diff --git a/app/services/reports/docx/draw_experiment.rb b/app/services/reports/docx/draw_experiment.rb
index e02d018a7..d7355ab36 100644
--- a/app/services/reports/docx/draw_experiment.rb
+++ b/app/services/reports/docx/draw_experiment.rb
@@ -4,6 +4,7 @@ module Reports::Docx::DrawExperiment
def draw_experiment(subject)
color = @color
link_style = @link_style
+ settings = @settings
scinote_url = @scinote_url
experiment = subject.experiment
return unless can_read_experiment?(@user, experiment)
@@ -15,8 +16,10 @@ module Reports::Docx::DrawExperiment
end
@docx.p do
- text I18n.t('projects.reports.elements.experiment.user_time',
- code: experiment.code, timestamp: I18n.l(experiment.created_at, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.experiment.user_time',
+ code: experiment.code, timestamp: I18n.l(experiment.created_at, format: :full)), color: color[:gray]
+ end
if experiment.archived?
text ' | '
text I18n.t('search.index.archived'), color: color[:gray]
diff --git a/app/services/reports/docx/draw_my_module.rb b/app/services/reports/docx/draw_my_module.rb
index e85ccf701..a174a6171 100644
--- a/app/services/reports/docx/draw_my_module.rb
+++ b/app/services/reports/docx/draw_my_module.rb
@@ -4,6 +4,7 @@ module Reports::Docx::DrawMyModule
def draw_my_module(subject, without_results: false, without_repositories: false)
color = @color
link_style = @link_style
+ settings = @settings
scinote_url = @scinote_url
my_module = subject.my_module
tags = my_module.tags.order(:id)
@@ -16,8 +17,10 @@ module Reports::Docx::DrawMyModule
end
@docx.p do
- text I18n.t('projects.reports.elements.module.user_time', code: my_module.code,
- timestamp: I18n.l(my_module.created_at, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.module.user_time', code: my_module.code,
+ timestamp: I18n.l(my_module.created_at, format: :full)), color: color[:gray]
+ end
if my_module.archived?
text ' | '
text I18n.t('search.index.archived'), color: color[:gray]
@@ -38,22 +41,24 @@ module Reports::Docx::DrawMyModule
end
end
- status = my_module.my_module_status
- @docx.p do
- text I18n.t('projects.reports.elements.module.status')
- text ' '
- text "[#{status.name}]", color: (status.light_color? ? '000000' : status.color.delete('#'))
- if my_module.completed?
- text " #{I18n.t('my_modules.states.completed')} #{I18n.l(my_module.completed_on, format: :full)}"
- end
- end
-
- if tags.present?
+ unless settings['exclude_metadata']
+ status = my_module.my_module_status
@docx.p do
- text I18n.t('projects.reports.elements.module.tags_header')
- tags.each do |tag|
- text ' '
- text "[#{tag.name}]", color: tag.color.delete('#')
+ text I18n.t('projects.reports.elements.module.status')
+ text ' '
+ text "[#{status.name}]", color: (status.light_color? ? '000000' : status.color.delete('#'))
+ if my_module.completed?
+ text " #{I18n.t('my_modules.states.completed')} #{I18n.l(my_module.completed_on, format: :full)}"
+ end
+ end
+
+ if tags.present?
+ @docx.p do
+ text I18n.t('projects.reports.elements.module.tags_header')
+ tags.each do |tag|
+ text ' '
+ text "[#{tag.name}]", color: tag.color.delete('#')
+ end
end
end
end
diff --git a/app/services/reports/docx/draw_my_module_protocol.rb b/app/services/reports/docx/draw_my_module_protocol.rb
index 2096569ff..04d03800c 100644
--- a/app/services/reports/docx/draw_my_module_protocol.rb
+++ b/app/services/reports/docx/draw_my_module_protocol.rb
@@ -12,8 +12,10 @@ module Reports::Docx::DrawMyModuleProtocol
end
if @settings.dig('task', 'protocol', 'description') && protocol.description.present?
- @docx.p I18n.t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code,
- timestamp: I18n.l(protocol.created_at, format: :full)), color: @color[:gray]
+ unless @settings['exclude_metadata']
+ @docx.p I18n.t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code,
+ timestamp: I18n.l(protocol.created_at, format: :full)), color: @color[:gray]
+ end
html = custom_auto_link(protocol.description, team: @report_team)
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
link_style: @link_style }).html_to_word_converter(html)
diff --git a/app/services/reports/docx/draw_project_header.rb b/app/services/reports/docx/draw_project_header.rb
index defa8e36e..56e2b6569 100644
--- a/app/services/reports/docx/draw_project_header.rb
+++ b/app/services/reports/docx/draw_project_header.rb
@@ -15,10 +15,12 @@ module Reports::Docx::DrawProjectHeader
link_style
end
- @docx.p do
- text I18n.t('projects.reports.elements.project_header.user_time', code: project.code,
- timestamp: I18n.l(project.created_at, format: :full)), color: color[:gray]
- br
+ unless @settings['exclude_metadata']
+ @docx.p do
+ text I18n.t('projects.reports.elements.project_header.user_time', code: project.code,
+ timestamp: I18n.l(project.created_at, format: :full)), color: color[:gray]
+ br
+ end
end
end
end
diff --git a/app/services/reports/docx/draw_result_asset.rb b/app/services/reports/docx/draw_result_asset.rb
index 030de2591..80520c4c7 100644
--- a/app/services/reports/docx/draw_result_asset.rb
+++ b/app/services/reports/docx/draw_result_asset.rb
@@ -25,8 +25,10 @@ module Reports::Docx::DrawResultAsset
end
text " #{I18n.t('search.index.archived')} ", bold: true if result.archived?
text ' ' + I18n.t('projects.reports.elements.result_asset.file_name', file: asset.file_name)
- text ' ' + I18n.t('projects.reports.elements.result_asset.user_time',
- user: result.user.full_name, timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text ' ' + I18n.t('projects.reports.elements.result_asset.user_time',
+ user: result.user.full_name, timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ end
if settings.dig(:task, :file_results_previews) && ActiveStorageFileUtil.previewable_document?(asset&.file&.blob)
text " #{I18n.t('projects.reports.elements.result_asset.full_preview_attached')}", color: color[:gray]
diff --git a/app/services/reports/docx/draw_result_table.rb b/app/services/reports/docx/draw_result_table.rb
index 661d41a46..0d3923623 100644
--- a/app/services/reports/docx/draw_result_table.rb
+++ b/app/services/reports/docx/draw_result_table.rb
@@ -5,6 +5,7 @@ module Reports::Docx::DrawResultTable
result = element.result
table = element.orderable.table
timestamp = table.created_at
+ settings = @settings
color = @color
obj = self
table_data = JSON.parse(table.contents_utf_8)['data']
@@ -40,8 +41,10 @@ module Reports::Docx::DrawResultTable
@docx.p do
text I18n.t 'projects.reports.elements.result_table.table_name', name: table.name
text ' '
- text I18n.t('projects.reports.elements.result_table.user_time',
- timestamp: I18n.l(timestamp, format: :full), user: result.user.full_name), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.result_table.user_time',
+ timestamp: I18n.l(timestamp, format: :full), user: result.user.full_name), color: color[:gray]
+ end
end
end
end
diff --git a/app/services/reports/docx/draw_result_text.rb b/app/services/reports/docx/draw_result_text.rb
index 2ab606a7e..1dbfe17d5 100644
--- a/app/services/reports/docx/draw_result_text.rb
+++ b/app/services/reports/docx/draw_result_text.rb
@@ -4,12 +4,15 @@ module Reports::Docx::DrawResultText
def draw_result_text(element)
result_text = element.orderable
timestamp = element.created_at
+ settings = @settings
color = @color
@docx.p do
text result_text.name.presence || '', italic: true
text ' '
- text I18n.t('projects.reports.elements.result_text.user_time',
- timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.result_text.user_time',
+ timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ end
end
html = custom_auto_link(result_text.text, team: @report_team)
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
diff --git a/app/services/reports/docx/draw_results.rb b/app/services/reports/docx/draw_results.rb
index 0baedb9cf..c35942da8 100644
--- a/app/services/reports/docx/draw_results.rb
+++ b/app/services/reports/docx/draw_results.rb
@@ -3,6 +3,7 @@
module Reports::Docx::DrawResults
def draw_results(my_module)
color = @color
+ settings = @settings
return unless can_read_my_module?(@user, my_module)
if my_module.results.any? && (%w(file_results table_results text_results).any? { |k| @settings.dig('task', k) })
@@ -11,9 +12,11 @@ module Reports::Docx::DrawResults
@docx.p do
text result.name.presence || I18n.t('projects.reports.unnamed'), italic: true
text " #{I18n.t('search.index.archived')} ", bold: true if result.archived?
- text I18n.t('projects.reports.elements.result.user_time',
- timestamp: I18n.l(result.created_at, format: :full),
- user: result.user.full_name), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.result.user_time',
+ timestamp: I18n.l(result.created_at, format: :full),
+ user: result.user.full_name), color: color[:gray]
+ end
end
draw_result_asset(result, @settings) if @settings.dig('task', 'file_results')
result.result_orderable_elements.each do |element|
diff --git a/app/services/reports/docx/draw_step.rb b/app/services/reports/docx/draw_step.rb
index 6d4e27da6..b2892ba6a 100644
--- a/app/services/reports/docx/draw_step.rb
+++ b/app/services/reports/docx/draw_step.rb
@@ -6,6 +6,7 @@ module Reports::Docx::DrawStep
step_type_str = step.completed ? 'completed' : 'uncompleted'
user = (step.completed? && step.last_modified_by) || step.user
timestamp = step.completed ? step.completed_on : step.created_at
+ settings = @settings
@docx.p
@docx.h4(
"#{I18n.t('projects.reports.elements.step.step_pos', pos: step.position_plus_one)} #{step.name}"
@@ -17,11 +18,13 @@ module Reports::Docx::DrawStep
text I18n.t('protocols.steps.uncompleted'), color: color[:gray], bold: true
end
text ' | '
- text I18n.t(
- "projects.reports.elements.step.#{step_type_str}.user_time",
- user: user.full_name,
- timestamp: I18n.l(timestamp, format: :full)
- ), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t(
+ "projects.reports.elements.step.#{step_type_str}.user_time",
+ user: user.full_name,
+ timestamp: I18n.l(timestamp, format: :full)
+ ), color: color[:gray]
+ end
end
step.step_orderable_elements.order(:position).each do |element|
diff --git a/app/services/reports/docx/draw_step_asset.rb b/app/services/reports/docx/draw_step_asset.rb
index 8d83ca221..fab9c36f6 100644
--- a/app/services/reports/docx/draw_step_asset.rb
+++ b/app/services/reports/docx/draw_step_asset.rb
@@ -5,6 +5,7 @@ module Reports::Docx::DrawStepAsset
timestamp = asset.created_at
asset_url = Rails.application.routes.url_helpers.asset_download_url(asset)
color = @color
+ settings = @settings
@docx.p
begin
@@ -23,8 +24,10 @@ module Reports::Docx::DrawStepAsset
italic true
end
text ' '
- text I18n.t('projects.reports.elements.step_asset.user_time',
- timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.step_asset.user_time',
+ timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ end
end
end
end
diff --git a/app/services/reports/docx/draw_step_checklist.rb b/app/services/reports/docx/draw_step_checklist.rb
index e2662e60e..c6e946e5b 100644
--- a/app/services/reports/docx/draw_step_checklist.rb
+++ b/app/services/reports/docx/draw_step_checklist.rb
@@ -4,6 +4,7 @@ module Reports::Docx::DrawStepChecklist
def draw_step_checklist(checklist)
team = @report_team
user = @user
+ settings = @settings
items = checklist.checklist_items
timestamp = checklist.created_at
@@ -16,8 +17,10 @@ module Reports::Docx::DrawStepChecklist
I18n.t('projects.reports.elements.step_checklist.checklist_name', name: checklist.name)
).text, italic: true
text ' '
- text I18n.t('projects.reports.elements.step_checklist.user_time',
- timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.step_checklist.user_time',
+ timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ end
end
if items.any?
@docx.ul do
diff --git a/app/services/reports/docx/draw_step_table.rb b/app/services/reports/docx/draw_step_table.rb
index a0826741a..8b3b4909b 100644
--- a/app/services/reports/docx/draw_step_table.rb
+++ b/app/services/reports/docx/draw_step_table.rb
@@ -4,6 +4,7 @@ module Reports::Docx::DrawStepTable
def draw_step_table(table, table_type)
color = @color
timestamp = table.created_at
+ settings = @settings
obj = self
table_data = JSON.parse(table.contents_utf_8)['data']
table_data = obj.add_headers_to_table(table_data, table_type == 'step_well_plates_table')
@@ -39,8 +40,10 @@ module Reports::Docx::DrawStepTable
@docx.p do
text I18n.t("projects.reports.elements.#{table_type}.table_name", name: table.name), italic: true
text ' '
- text I18n.t("projects.reports.elements.#{table_type}.user_time",
- timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t("projects.reports.elements.#{table_type}.user_time",
+ timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ end
end
end
end
diff --git a/app/services/reports/docx/draw_step_text.rb b/app/services/reports/docx/draw_step_text.rb
index 978386a94..6218595a0 100644
--- a/app/services/reports/docx/draw_step_text.rb
+++ b/app/services/reports/docx/draw_step_text.rb
@@ -5,11 +5,14 @@ module Reports::Docx::DrawStepText
step_text = element.orderable
timestamp = element.created_at
color = @color
+ settings = @settings
@docx.p do
text step_text.name.presence || '', italic: true
text ' '
- text I18n.t('projects.reports.elements.result_text.user_time',
- timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ unless settings['exclude_metadata']
+ text I18n.t('projects.reports.elements.result_text.user_time',
+ timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
+ end
end
if step_text.text.present?
html = custom_auto_link(step_text.text, team: @report_team)
diff --git a/app/views/reports/elements/_experiment_element.html.erb b/app/views/reports/elements/_experiment_element.html.erb
index 8ef08378e..475c96b7b 100644
--- a/app/views/reports/elements/_experiment_element.html.erb
+++ b/app/views/reports/elements/_experiment_element.html.erb
@@ -9,7 +9,7 @@
<%= t('search.index.archived') %>
<% end %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t('projects.reports.elements.experiment.user_time', code: experiment.code, timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/elements/_my_module_element.html.erb b/app/views/reports/elements/_my_module_element.html.erb
index 562495418..5ad3cee73 100644
--- a/app/views/reports/elements/_my_module_element.html.erb
+++ b/app/views/reports/elements/_my_module_element.html.erb
@@ -9,7 +9,7 @@
<%= t('search.index.archived') %>
<% end %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t('projects.reports.elements.module.user_time', code: my_module.code, timestamp: l(timestamp, format: :full)) %>
@@ -24,21 +24,23 @@
<%= t('projects.reports.elements.module.due_date', due_date: l(my_module.due_date, format: :full)) %>
<% end %>
-
- <% status = my_module.my_module_status %>
- <%= t('projects.reports.elements.module.status') %>
-
- <%= status.name %>
-
- <% if my_module.completed? %>
-
- <%= t('my_modules.states.completed') %>
- <%= l(my_module.completed_on, format: :full) %>
+ <% unless @settings['exclude_metadata'] %>
+
+ <% status = my_module.my_module_status %>
+ <%= t('projects.reports.elements.module.status') %>
+
+ <%= status.name %>
- <% end %>
-
- <% unless @settings.dig('exclude_metadata') %>
+ <% if my_module.completed? %>
+
+ <%= t('my_modules.states.completed') %>
+ <%= l(my_module.completed_on, format: :full) %>
+
+ <% end %>
+
+ <% end %>
+ <% unless @settings['exclude_metadata'] %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t("projects.reports.elements.result_text.user_time", timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/elements/_my_module_step_element.html.erb b/app/views/reports/elements/_my_module_step_element.html.erb
index 15f6d32ea..2be53b1a9 100644
--- a/app/views/reports/elements/_my_module_step_element.html.erb
+++ b/app/views/reports/elements/_my_module_step_element.html.erb
@@ -10,7 +10,7 @@
<%= t('projects.reports.elements.step.step_pos', pos: (step.position_plus_one)) %> <%= step.name %>
<%= step_status_label(step) %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t("projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/elements/_project_header_element.html.erb b/app/views/reports/elements/_project_header_element.html.erb
index 735afe95e..9e355d6d9 100644
--- a/app/views/reports/elements/_project_header_element.html.erb
+++ b/app/views/reports/elements/_project_header_element.html.erb
@@ -7,7 +7,7 @@
<%= t('search.index.archived') %>
<% end %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t('projects.reports.elements.project_header.user_time', code: project.code, timestamp: l(project.created_at, format: :full)) %>
diff --git a/app/views/reports/elements/_step_asset_element.html.erb b/app/views/reports/elements/_step_asset_element.html.erb
index 75ea45762..880ab97ee 100644
--- a/app/views/reports/elements/_step_asset_element.html.erb
+++ b/app/views/reports/elements/_step_asset_element.html.erb
@@ -18,7 +18,7 @@
<% end %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t('projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/elements/_step_checklist_element.html.erb b/app/views/reports/elements/_step_checklist_element.html.erb
index 9a7917aa3..1951fde55 100644
--- a/app/views/reports/elements/_step_checklist_element.html.erb
+++ b/app/views/reports/elements/_step_checklist_element.html.erb
@@ -9,7 +9,7 @@
team: current_team,
base64_encoded_imgs: export_all) %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t('projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/elements/_step_table_element.html.erb b/app/views/reports/elements/_step_table_element.html.erb
index 1cc9c8b3c..dfda2ac14 100644
--- a/app/views/reports/elements/_step_table_element.html.erb
+++ b/app/views/reports/elements/_step_table_element.html.erb
@@ -18,7 +18,7 @@
<% end %>
<% end %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t("projects.reports.elements.#{table_type}.user_time", timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/elements/_step_text_element.html.erb b/app/views/reports/elements/_step_text_element.html.erb
index 9a62410c3..8c8ff72eb 100644
--- a/app/views/reports/elements/_step_text_element.html.erb
+++ b/app/views/reports/elements/_step_text_element.html.erb
@@ -8,7 +8,7 @@
<% end %>
- <% unless @settings.dig('exclude_metadata') %>
+ <% unless @settings['exclude_metadata'] %>
<%= t("projects.reports.elements.step_text.user_time", timestamp: l(timestamp, format: :full)) %>
diff --git a/config/database.yml b/config/database.yml
index a44a2ec67..c7f72cd5c 100644
--- a/config/database.yml
+++ b/config/database.yml
@@ -35,7 +35,6 @@ development:
# The password associated with the postgres role (username).
# password: mysecretpassword
-
# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
From dddf2be610e7a28790f0b79239a7b95605596b13 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Tue, 20 Aug 2024 15:01:42 +0200
Subject: [PATCH 05/96] Update caracal version [SCI-10985]
---
Gemfile | 3 +--
Gemfile.lock | 16 +++++++++++-----
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/Gemfile b/Gemfile
index 453dea286..62c5bdb79 100644
--- a/Gemfile
+++ b/Gemfile
@@ -47,8 +47,7 @@ gem 'aspector' # Aspect-oriented programming for Rails
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces AR
gem 'bcrypt', '~> 3.1.10'
# gem 'caracal'
-# gem 'caracal', git: 'https://github.com/scinote-eln/caracal.git', branch: 'rubyzip2' # Build docx report
-gem 'caracal_the_curve', '~> 1.4', '>= 1.4.6'
+gem 'caracal', git: 'https://github.com/scinote-eln/caracal.git', branch: 'custom-docx-reports' # Build docx report
gem 'caxlsx' # Build XLSX files
gem 'deface', '~> 1.9'
gem 'down', '~> 5.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 5a29368f2..0baa4846f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -22,6 +22,16 @@ GIT
docile (>= 1.1.0)
rails (>= 4)
+GIT
+ remote: https://github.com/scinote-eln/caracal.git
+ revision: f8e4c279adfee7801eb1024e1d6a18bb06c9c76a
+ branch: custom-docx-reports
+ specs:
+ caracal (1.4.1)
+ nokogiri (~> 1.6)
+ rubyzip (>= 2.3)
+ tilt (>= 1.4)
+
GIT
remote: https://github.com/scinote-eln/img2zpl
revision: 23d61cfc3e90ac4caa62dd08546fa0d7590a5140
@@ -217,10 +227,6 @@ GEM
capybara-email (3.0.2)
capybara (>= 2.4, < 4.0)
mail
- caracal_the_curve (1.4.6)
- nokogiri (~> 1.6)
- rubyzip (>= 1.1.0, < 3.0)
- tilt (>= 1.4)
case_transform (0.2)
activesupport
caxlsx (4.0.0)
@@ -799,7 +805,7 @@ DEPENDENCIES
canaid!
capybara
capybara-email
- caracal_the_curve (~> 1.4, >= 1.4.6)
+ caracal!
caxlsx
cssbundling-rails
cucumber-rails
From f912f6bc41502760b7659c47e7da33ce456f0017 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Tue, 27 Aug 2024 13:40:10 +0200
Subject: [PATCH 06/96] Fix docx templates [SCI-10988]
---
.../reports/repositories_input_component.rb | 5 +-
app/services/reports/docx/draw_step.rb | 2 +-
.../docx_templates/custom_template/docx.rb | 188 ------------------
.../custom_template/edit.html.erb | 57 ------
.../docx_templates/custom_template/name.txt | 1 -
5 files changed, 3 insertions(+), 250 deletions(-)
delete mode 100644 app/views/reports/docx_templates/custom_template/docx.rb
delete mode 100644 app/views/reports/docx_templates/custom_template/edit.html.erb
delete mode 100644 app/views/reports/docx_templates/custom_template/name.txt
diff --git a/app/components/reports/repositories_input_component.rb b/app/components/reports/repositories_input_component.rb
index c7909d8c7..f168cc396 100644
--- a/app/components/reports/repositories_input_component.rb
+++ b/app/components/reports/repositories_input_component.rb
@@ -2,10 +2,9 @@
module Reports
class RepositoriesInputComponent < TemplateValueComponent
- def initialize(report:, name:, label:, placeholder: nil, editing: true, displayed_field: :name)
+ def initialize(report:, name:, label:, placeholder: nil, editing: true, displayed_field: :name, user: nil)
super(report: report, name: name, label: label, placeholder: placeholder, editing: editing)
-
- live_repositories = Repository.accessible_by_teams(report.team).sort_by { |r| r.name.downcase }
+ live_repositories = Repository.viewable_by_user(user, report.team).sort_by { |r| r.name.downcase }
snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
.where(team: report.team)
.where.not(original_repository: live_repositories)
diff --git a/app/services/reports/docx/draw_step.rb b/app/services/reports/docx/draw_step.rb
index b2892ba6a..ef762fcb9 100644
--- a/app/services/reports/docx/draw_step.rb
+++ b/app/services/reports/docx/draw_step.rb
@@ -17,8 +17,8 @@ module Reports::Docx::DrawStep
else
text I18n.t('protocols.steps.uncompleted'), color: color[:gray], bold: true
end
- text ' | '
unless settings['exclude_metadata']
+ text ' | '
text I18n.t(
"projects.reports.elements.step.#{step_type_str}.user_time",
user: user.full_name,
diff --git a/app/views/reports/docx_templates/custom_template/docx.rb b/app/views/reports/docx_templates/custom_template/docx.rb
deleted file mode 100644
index b2e16276a..000000000
--- a/app/views/reports/docx_templates/custom_template/docx.rb
+++ /dev/null
@@ -1,188 +0,0 @@
-# frozen_string_literal: true
-
-module CustomTemplateDocx
- def prepare_docx
- report_name = get_template_value('custom_docx_report_name')
- report_number = get_template_value('custom_docx_report_number')
-
- @project_members = @report.project&.users
-
- report_authors = @project_members.where(id: get_template_value('custom_docx_author[]')).pluck(:full_name).join(', ')
- report_reviewers = @project_members.where(id: get_template_value('custom_docx_reviewer[]')).pluck(:full_name).join(', ')
- report_author_role = get_template_value('custom_docx_author_role')
- report_reviewer_role = get_template_value('custom_docx_reviewer_role')
-
- @docx.header do |header|
- header.table [[report_name, 'custom report']] do
- border_size 1
- cell_style cols[0], width: 8000
- cell_style cols[1], width: 2800
- end
- end
-
- @docx.footer do |footer|
- pages = Caracal::Core::Models::TableCellModel.new do
- p do
- field :page
- text ' of '
- field :numpages
- end
- end
- footer.table [['Confidential', pages]] do
- border_top do
- size 1
- end
- cell_style cols[0], width: 9500
- cell_style cols[1], width: 1000
- end
- end
-
- @docx.p
-
- logo_data = File.read(Rails.root.join('app/assets/images/scinote_logo.png'))
-
- c1 = Caracal::Core::Models::TableCellModel.new do
- p report_name, bold: true
- p ''
- end
-
- c2 = Caracal::Core::Models::TableCellModel.new do
- img 'logo.png' do
- data logo_data
- height 20
- width 100
- align :left
- end
- end
-
- c3 = Caracal::Core::Models::TableCellModel.new do
- p "Author: #{report_authors}"
- p "Role: #{report_author_role}"
- end
-
- c4 = Caracal::Core::Models::TableCellModel.new do
- p "Reviewer: #{report_reviewers}"
- p "Role: #{report_reviewer_role}"
- end
-
- c5 = Caracal::Core::Models::TableCellModel.new do
- p "Report number:"
- p report_number
- end
-
- @docx.table [[c1, c2], [c3, c4, c5]] do
- border_size 2
- cell_style rows[0], width: 3500
- cell_style rows[1], width: 3500
- cell_style rows[0][0], colspan: 2
- end
-
- @docx.p
-
- @docx.table_of_contents do |toc|
- toc.title 'Table of Contents'
- toc.opts 'TOC \o "1-4" \h \z \u \t "Heading 5,1"'
- end
-
- @docx.page
-
- my_modules_elements = []
- @report.root_elements.each do |subject|
- my_modules_elements += subject.children.active if subject.type_of == 'experiment'
- end
-
- @my_modules = MyModule.where(id: my_modules_elements.map { |element| element.my_module.id })
-
- @docx.h1 'Chapter 1'
- @docx.h2 'Sub chapter 1' if get_template_value('custom_docx_sub_chapter_1')
- @docx.h2 'Sub chapter 2' if get_template_value('custom_docx_sub_chapter_2')
- @docx.h1 'Chapter 2'
- if get_template_value('custom_docx_sub_chapter_3')
- @docx.h2 'Sub chapter 3 with inventory'
- draw_repositories(get_template_value('custom_docx_sub_chapter_3_inventories[]'))
- end
- if get_template_value('custom_docx_sub_chapter_4')
- @docx.h2 'Sub chapter 4 with inventory'
- draw_repositories(get_template_value('custom_docx_sub_chapter_4_inventories[]'))
- end
- @docx.h2 'Sub chapter 5' if get_template_value('custom_docx_sub_chapter_5')
- @docx.h2 'Sub chapter 6' if get_template_value('custom_docx_sub_chapter_6')
- @docx.h2 'Sub chapter 7' if get_template_value('custom_docx_sub_chapter_7')
- @docx.h1 'Chapter 3'
- if get_template_value('custom_docx_sub_chapter_8')
- @docx.h2 'Sub chapter 8 with task'
- my_modules_elements.each do |element|
- draw_my_module(element, without_results: true, without_repositories: true)
- end
- end
- @docx.h2 'Sub chapter 9' if get_template_value('custom_docx_sub_chapter_9')
- @docx.h2 'Sub chapter 10' if get_template_value('custom_docx_sub_chapter_10')
- @docx.h2 'Sub chapter 11' if get_template_value('custom_docx_sub_chapter_11')
- if get_template_value('custom_docx_sub_chapter_12')
- @docx.h2 'Sub chapter 12'
- @docx.h3 'Sub sub chapter 1' if get_template_value('custom_docx_sub_sub_chapter_1')
- @docx.h3 'Sub sub chapter 2' if get_template_value('custom_docx_sub_sub_chapter_2')
- end
- @docx.h1 'Chapter 4'
- if get_template_value('custom_docx_sub_chapter_13')
- @docx.h2 'Sub chapter 13 with results'
- my_modules_elements.each do |element|
- draw_results(element.my_module)
- end
- end
- @docx.h2 'Sub chapter 14' if get_template_value('custom_docx_sub_chapter_14')
- @docx.h2 'Sub chapter 15' if get_template_value('custom_docx_sub_chapter_15')
- @docx.h2 'Sub chapter 16' if get_template_value('custom_docx_sub_chapter_16')
- @docx.h2 'Sub chapter 17' if get_template_value('custom_docx_sub_chapter_17')
- @docx.h1 'Chapter 5'
- end
-
- def repository_docx_json(repository, rows)
- headers = [
- I18n.t('repositories.table.id'),
- I18n.t('repositories.table.row_name'),
- I18n.t('repositories.table.added_on'),
- I18n.t('repositories.table.added_by')
- ]
- custom_columns = []
- return false unless repository
-
- repository.repository_columns.order(:id).each do |column|
- headers.push(column.name)
- custom_columns.push(column.id)
- end
-
- records = repository.repository_rows.where(id: rows)
- .select(:id, :name, :created_at, :created_by_id, :repository_id, :parent_id, :archived)
- { headers: headers, rows: records, custom_columns: custom_columns }
- end
-
- def load_repositories(repositories_id)
- live_repositories = Repository.accessible_by_teams(@report.team).where(id: repositories_id).sort_by { |r| r.name.downcase }
- snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
- .where(team: @report.team)
- .where(parent_id: repositories_id)
- .where.not(original_repository: live_repositories)
- .select('DISTINCT ON ("repositories"."parent_id") "repositories".*')
- .sort_by { |r| r.name.downcase }
- live_repositories + snapshots_of_deleted
- end
-
- def draw_repositories(repositories_id)
- load_repositories(repositories_id).each do |repository|
- rows = repository.repository_rows.where(id: @my_modules.joins(:my_module_repository_rows).select(:repository_row_id)).select(:id)
- repository_data = repository_docx_json(repository, rows)
-
- next unless repository_data[:rows].any? && can_read_repository?(@user, repository)
-
- table = prepare_row_columns(repository_data, nil, repository)
-
- @docx.p
- @docx.p repository.name, bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
- @docx.table table, border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
-
- @docx.p
- @docx.p
- end
- end
-end
diff --git a/app/views/reports/docx_templates/custom_template/edit.html.erb b/app/views/reports/docx_templates/custom_template/edit.html.erb
deleted file mode 100644
index 6bef2a79e..000000000
--- a/app/views/reports/docx_templates/custom_template/edit.html.erb
+++ /dev/null
@@ -1,57 +0,0 @@
-<% content_for :toc do %>
- Chapter 1
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_1, label: 'Sub chapter 1') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_2, label: 'Sub chapter 2') %>
-
- Chapter 2
-
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_3, label: 'Sub chapter 3 with inventory') %>
-
- <%= render Reports::RepositoriesInputComponent.new(report: report, name: 'custom_docx_sub_chapter_3_inventories[]', label: 'Inventories') %>
-
-
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_4, label: 'Sub chapter 4 with inventory') %>
-
- <%= render Reports::RepositoriesInputComponent.new(report: report, name: 'custom_docx_sub_chapter_4_inventories[]', label: 'Inventories') %>
-
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_5, label: 'Sub chapter 5') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_6, label: 'Sub chapter 6') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_7, label: 'Sub chapter 7') %>
-
- Chapter 3
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_8, label: 'Sub chapter 8 with task') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_9, label: 'Sub chapter 9') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_10, label: 'Sub chapter 10') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_11, label: 'Sub chapter 11') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_12, label: 'Sub chapter 12') %>
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_sub_chapter_1, label: 'Sub sub chapter 1') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_sub_chapter_2, label: 'Sub sub chapter 2') %>
-
-
- Chapter 4
-
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_13, label: 'Sub chapter 13 with results') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_14, label: 'Sub chapter 14') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_15, label: 'Sub chapter 15') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_16, label: 'Sub chapter 16') %>
- <%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_17, label: 'Sub chapter 17') %>
-
- Chapter 5
-<% end %>
-
-<% content_for :cover do %>
- <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_report_name, label: 'Report name') %>
- <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_report_number, label: 'Report number') %>
-
- <%= render Reports::ProjectMembersInputComponent.new(report: report, name: 'custom_docx_author[]', label: 'Author') %>
- <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_author_role, label: 'Author Role') %>
-
- <%= render Reports::ProjectMembersInputComponent.new(report: report, name: 'custom_docx_reviewer[]', label: 'Reviewer') %>
- <%= render Reports::TextInputComponent.new(report: report, name: :custom_docx_reviewer_role, label: 'Reviewer Role') %>
-<% end %>
diff --git a/app/views/reports/docx_templates/custom_template/name.txt b/app/views/reports/docx_templates/custom_template/name.txt
deleted file mode 100644
index 0ad39c916..000000000
--- a/app/views/reports/docx_templates/custom_template/name.txt
+++ /dev/null
@@ -1 +0,0 @@
-Custom Template
From dddffc11cd737df18669bf9da79a7140097b14ac Mon Sep 17 00:00:00 2001
From: Andrej
Date: Wed, 28 Aug 2024 11:57:41 +0200
Subject: [PATCH 07/96] Improve report wizards [SCI-10989]
---
app/assets/javascripts/reports/new.js | 13 ++++++--
app/controllers/reports_controller.rb | 32 ++++++++++++++++++-
app/helpers/reports_helper.rb | 4 +++
app/services/reports/docx.rb | 2 +-
.../reports/template_values_editor.html.erb | 6 +++-
.../wizard/_no_template_values.html.erb | 6 +++-
.../_project_template_selector.html.erb | 4 ++-
config/locales/en.yml | 6 ++--
8 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js
index 519bae098..168aab5de 100644
--- a/app/assets/javascripts/reports/new.js
+++ b/app/assets/javascripts/reports/new.js
@@ -1258,7 +1258,8 @@ function reportHandsonTableConverter() {
function reCheckContinueButton() {
if (dropdownSelector.getValues('#projectSelector').length > 0
&& dropdownSelector.getValues('#templateSelector').length > 0
- && dropdownSelector.getValues('#docxTemplateSelector').length > 0) {
+ && (dropdownSelector.getValues('#docxTemplateSelector').length > 0
+ || $('#docxTemplateSelector').closest('.hidden').length > 0)) {
$('.continue-button').attr('disabled', false);
} else {
$('.continue-button').attr('disabled', true);
@@ -1281,6 +1282,12 @@ function reportHandsonTableConverter() {
if (dropdownSelector.getValues('#projectSelector').length > 0) {
dropdownSelector.enableSelector('#templateSelector');
dropdownSelector.enableSelector('#docxTemplateSelector');
+ if ($('#templateSelector').data('defaultTemplate')) {
+ dropdownSelector.selectValues('#templateSelector', $('#templateSelector').data('defaultTemplate'));
+ }
+ if ($('#docxTemplateSelector').data('defaultTemplate')) {
+ dropdownSelector.selectValues('#docxTemplateSelector', $('#docxTemplateSelector').data('defaultTemplate'));
+ }
} else {
dropdownSelector.selectValues('#templateSelector', '');
dropdownSelector.disableSelector('#templateSelector');
@@ -1354,7 +1361,7 @@ function reportHandsonTableConverter() {
}
function loadTemplate() {
- let template = $('#templateSelector').val();
+ const template = dropdownSelector.getValues('#templateSelector');
let params = {
project_id: dropdownSelector.getValues('#projectSelector'),
template: template
@@ -1384,7 +1391,7 @@ function reportHandsonTableConverter() {
}
function loadDocxTemplate() {
- let template = $('#docxTemplateSelector').val();
+ const template = dropdownSelector.getValues('#docxTemplateSelector');
let params = {
project_id: dropdownSelector.getValues('#projectSelector'),
template: template
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index bb13046b4..7bb30bfe8 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -18,7 +18,8 @@ class ReportsController < ApplicationController
before_action :check_create_permissions, only: %i(new create)
before_action :check_manage_permissions, only: %i(edit update generate_pdf generate_docx)
before_action :switch_team_with_param, only: :index
- after_action :generate_pdf_report, only: %i(create update generate_pdf)
+ after_action :generate_pdf_report, only: %i(generate_pdf)
+ after_action :generate_report, only: %i(create update)
# Index showing all reports of a single project
def index
@@ -44,6 +45,8 @@ class ReportsController < ApplicationController
def new_template_values
if Extends::REPORT_TEMPLATES.key?(params[:template]&.to_sym)
template = params[:template]
+ @type = :pdf
+ @template_name = Extends::REPORT_TEMPLATES[params[:template].to_sym]
else
return render_404
end
@@ -69,6 +72,7 @@ class ReportsController < ApplicationController
else
render json: {
html: render_to_string(partial: 'reports/wizard/no_template_values',
+ locals: { type: @type, template: @template_name },
formats: :html)
}
end
@@ -77,6 +81,8 @@ class ReportsController < ApplicationController
def new_docx_template_values
if Extends::DOCX_REPORT_TEMPLATES.key?(params[:template]&.to_sym)
template = params[:template]
+ @type = :docx
+ @template_name = Extends::DOCX_REPORT_TEMPLATES[params[:template].to_sym]
else
return render_404
end
@@ -102,6 +108,7 @@ class ReportsController < ApplicationController
else
render json: {
html: render_to_string(partial: 'reports/wizard/no_template_values',
+ locals: { type: @type, template: @template_name },
formats: :html)
}
end
@@ -363,6 +370,9 @@ class ReportsController < ApplicationController
.merge(MyModule.active)
.group(:id)
.select(:id, :name)
+ @default_template = Extends::REPORT_TEMPLATES.keys.first.to_s if Extends::REPORT_TEMPLATES.one?
+
+ @default_docx_template = Extends::DOCX_REPORT_TEMPLATES.keys.first.to_s if Extends::DOCX_REPORT_TEMPLATES.one? && custom_templates(Extends::DOCX_REPORT_TEMPLATES)
end
def check_project_read_permissions
@@ -430,6 +440,26 @@ class ReportsController < ApplicationController
Rails.logger.error e.message
end
+ def generate_docx_report
+ return unless @report.persisted?
+
+ @report.docx_processing!
+ log_activity(:generate_docx_report)
+
+ ensure_report_template!
+ Reports::DocxJob.perform_later(@report.id, user_id: current_user.id, root_url: root_url)
+ rescue ActiveRecord::ActiveRecordError => e
+ Rails.logger.error e.message
+ end
+
+ def generate_report
+ return unless @report.persisted?
+
+ generate_pdf_report
+
+ generate_docx_report if @report.settings['docx_template'].present? && custom_templates(Extends::DOCX_REPORT_TEMPLATES)
+ end
+
def ensure_report_template!
return if @report.settings['template'].present?
diff --git a/app/helpers/reports_helper.rb b/app/helpers/reports_helper.rb
index 7dcc85929..5a05d13e2 100644
--- a/app/helpers/reports_helper.rb
+++ b/app/helpers/reports_helper.rb
@@ -106,4 +106,8 @@ module ReportsHelper
experiment_element.experiment.description
end
end
+
+ def custom_templates(templates)
+ templates.any? { |template, _| template != :scinote_template }
+ end
end
diff --git a/app/services/reports/docx.rb b/app/services/reports/docx.rb
index 46445f338..72e6ce339 100644
--- a/app/services/reports/docx.rb
+++ b/app/services/reports/docx.rb
@@ -30,7 +30,7 @@ class Reports::Docx
@link_style = {}
@color = {}
@scinote_url = options[:scinote_url][0..-2]
- @template = @settings[:docx_template] || 'scinote_template'
+ @template = @settings[:docx_template].presence || 'scinote_template'
extend "#{@template.camelize}Docx".constantize
end
diff --git a/app/views/layouts/reports/template_values_editor.html.erb b/app/views/layouts/reports/template_values_editor.html.erb
index 225c32a4a..841b024ef 100644
--- a/app/views/layouts/reports/template_values_editor.html.erb
+++ b/app/views/layouts/reports/template_values_editor.html.erb
@@ -1,6 +1,10 @@
- <% unless @settings['exclude_metadata'] %>
+ <% unless @settings['exclude_timestamps'] %>
<%= t("projects.reports.elements.step_text.user_time", timestamp: l(timestamp, format: :full)) %>
diff --git a/app/views/reports/wizard/_third_step.html.erb b/app/views/reports/wizard/_third_step.html.erb
index d56af9b24..327c1d857 100644
--- a/app/views/reports/wizard/_third_step.html.erb
+++ b/app/views/reports/wizard/_third_step.html.erb
@@ -184,7 +184,7 @@
<%= t("projects.reports.wizard.third_step.additional_content") %>
-
+
/>
@@ -197,10 +197,20 @@
+
+
+
+
+ />
+
+
+ <%= t("projects.reports.wizard.third_step.exclude_timestamps") %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 3e481c9a8..f24bc62a7 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -853,7 +853,8 @@ en:
results_comments: "Result comments"
additional_content: "Additional content"
task_activity: "Include task activity"
- exclude_metadata: "Exclude metadata"
+ exclude_task_metadata: "Exclude task metadata"
+ exclude_timestamps: "Exclude timestamps"
archived: "[archived]"
deleted: "[deleted]"
From c128f2f0035dcd0dd4dfa32d0edc900402861503 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Thu, 5 Sep 2024 15:08:29 +0200
Subject: [PATCH 13/96] Check presence of template zip URL [SCI-10999]
---
config/initializers/report_template_loader.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/initializers/report_template_loader.rb b/config/initializers/report_template_loader.rb
index 1af443d04..380651833 100644
--- a/config/initializers/report_template_loader.rb
+++ b/config/initializers/report_template_loader.rb
@@ -5,7 +5,7 @@ require 'active_storage/service/s3_service'
template_zip_url_string = ENV.fetch('REPORT_TEMPLATES_ZIP_URL', nil)
-return unless template_zip_url_string
+return unless template_zip_url_string.present?
template_zip_url = URI.parse(template_zip_url_string)
contents = case template_zip_url.scheme
From 2ccf1abc91612793762770a6bc62e9c261d32c21 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Thu, 5 Sep 2024 16:21:39 +0200
Subject: [PATCH 14/96] Remove tag for attached files in docx [SCI-11027]
---
app/services/reports/docx/draw_result_asset.rb | 4 ----
1 file changed, 4 deletions(-)
diff --git a/app/services/reports/docx/draw_result_asset.rb b/app/services/reports/docx/draw_result_asset.rb
index 7eac0dff9..fc690977f 100644
--- a/app/services/reports/docx/draw_result_asset.rb
+++ b/app/services/reports/docx/draw_result_asset.rb
@@ -29,10 +29,6 @@ module Reports::Docx::DrawResultAsset
text ' ' + I18n.t('projects.reports.elements.result_asset.user_time',
user: result.user.full_name, timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
end
-
- if settings.dig(:task, :file_results_previews) && ActiveStorageFileUtil.previewable_document?(asset&.file&.blob)
- text " #{I18n.t('projects.reports.elements.result_asset.full_preview_attached')}", color: color[:gray]
- end
end
draw_result_comments(result) if @settings.dig('task', 'result_comments')
From a05c88569b5220477836c529458175972038ff33 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Thu, 5 Sep 2024 17:21:24 +0200
Subject: [PATCH 15/96] Require docx template files on initialization
[SCI-10999]
---
config/initializers/report_template_loader.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/config/initializers/report_template_loader.rb b/config/initializers/report_template_loader.rb
index 380651833..6461315f6 100644
--- a/config/initializers/report_template_loader.rb
+++ b/config/initializers/report_template_loader.rb
@@ -5,7 +5,7 @@ require 'active_storage/service/s3_service'
template_zip_url_string = ENV.fetch('REPORT_TEMPLATES_ZIP_URL', nil)
-return unless template_zip_url_string.present?
+return if template_zip_url_string.blank?
template_zip_url = URI.parse(template_zip_url_string)
contents = case template_zip_url.scheme
@@ -33,5 +33,7 @@ Zip::File.open_buffer(StringIO.new(contents)) do |zip|
path.open('wb') do |f|
f.write(entry.get_input_stream.read)
end
+
+ require path if entry.name.ends_with?('.rb')
end
end
From 8095b0731a3dca2ab272694ca79570d046f1b390 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Fri, 6 Sep 2024 11:15:34 +0200
Subject: [PATCH 16/96] Move template loading to a script [SCI-10999]
---
.../load_report_templates | 21 +++++++++++--------
1 file changed, 12 insertions(+), 9 deletions(-)
rename config/initializers/report_template_loader.rb => bin/load_report_templates (54%)
mode change 100644 => 100755
diff --git a/config/initializers/report_template_loader.rb b/bin/load_report_templates
old mode 100644
new mode 100755
similarity index 54%
rename from config/initializers/report_template_loader.rb
rename to bin/load_report_templates
index 6461315f6..8bb1c4f05
--- a/config/initializers/report_template_loader.rb
+++ b/bin/load_report_templates
@@ -1,39 +1,42 @@
-# frozen_string_literal: true
+#!/usr/bin/env ruby
require 'httparty'
-require 'active_storage/service/s3_service'
+require 'zip'
template_zip_url_string = ENV.fetch('REPORT_TEMPLATES_ZIP_URL', nil)
-return if template_zip_url_string.blank?
+return if template_zip_url_string.nil? || template_zip_url_string.empty?
template_zip_url = URI.parse(template_zip_url_string)
contents = case template_zip_url.scheme
when 'https'
HTTParty.get(template_zip_url).body
when 's3'
- ActiveStorage::Service::S3Service.new(
- bucket: template_zip_url.host
- ).download(template_zip_url.path[1..])
+ system("AWS_PAGER=\"\" aws s3api get-object --bucket #{template_zip_url.host} --key #{template_zip_url.path[1..]} ./report_templates.zip")
+ File.read('./report_templates.zip')
end
+puts "Loaded report templates zip from #{template_zip_url_string}"
+
root_folder = nil
Zip::File.open_buffer(StringIO.new(contents)) do |zip|
+ puts 'Extracting report templates...'
+
zip.each do |entry|
# set root zip folder
root_folder = entry.name and next if entry.name.count('/') == 1
# create path while omitting root zip folder
- path = Rails.root.join('app', 'views', 'reports', entry.name.sub(root_folder, ''))
+ path = Pathname.new("#{ENV.fetch('APP_HOME', '.')}/app/views/reports/#{entry.name.sub(root_folder, '')}")
path.dirname.mkpath
# don't try and write file if entry is a folder
- next if entry.name.ends_with?('/')
+ next if entry.name.end_with?('/')
path.open('wb') do |f|
f.write(entry.get_input_stream.read)
end
- require path if entry.name.ends_with?('.rb')
+ puts "Extracted #{path}"
end
end
From 9d7a0c268de3efbfbcba485bbc388da999f594af Mon Sep 17 00:00:00 2001
From: Andrej
Date: Mon, 9 Sep 2024 11:37:37 +0200
Subject: [PATCH 17/96] Exclude timestamps for docx reports for task results
[SCI-11017]
---
app/views/reports/elements/_my_module_element.html.erb | 8 +++++---
.../elements/_my_module_result_asset_element.html.erb | 2 +-
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/app/views/reports/elements/_my_module_element.html.erb b/app/views/reports/elements/_my_module_element.html.erb
index 17bcaf304..b8778e7a7 100644
--- a/app/views/reports/elements/_my_module_element.html.erb
+++ b/app/views/reports/elements/_my_module_element.html.erb
@@ -94,9 +94,11 @@
<% if @settings.dig('task', 'file_results') %>
<%= render partial: 'reports/elements/my_module_result_asset_element', locals: { result: result, report: report, export_all: export_all } %>
-
- <%= t('projects.reports.elements.result.user_time', user: result.user.full_name, timestamp: l(result.created_at, format: :full)) %>
-
+ <% unless @settings['exclude_timestamps'] %>
+
+ <%= t('projects.reports.elements.result.user_time', user: result.user.full_name, timestamp: l(result.created_at, format: :full)) %>
+
+ <% end %>
<% end %>
diff --git a/app/views/reports/elements/_my_module_result_asset_element.html.erb b/app/views/reports/elements/_my_module_result_asset_element.html.erb
index de71933c6..f4cd9e072 100644
--- a/app/views/reports/elements/_my_module_result_asset_element.html.erb
+++ b/app/views/reports/elements/_my_module_result_asset_element.html.erb
@@ -24,7 +24,7 @@
<%= link_to t('projects.reports.elements.download'), asset_download_url(asset, disposition: 'attachment'), class: 'download-link', target: :_blank %>
<% end %>
-
+
<% unless @settings['exclude_timestamps'] %>
<%= t("projects.reports.elements.result_asset.user_time", user: result.user.full_name, timestamp: l(timestamp, format: :full)) %>
From 388926e02126c0a2f7bd1e369c33af7daff671f8 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Mon, 29 Jul 2024 12:09:21 +0200
Subject: [PATCH 18/96] Add versioned file attachments to assets [SCI-10774]
---
app/controllers/api/v1/results_controller.rb | 2 +-
app/controllers/asset_sync_controller.rb | 4 ++--
.../gene_sequence_assets_controller.rb | 2 +-
app/controllers/result_assets_controller.rb | 2 +-
app/controllers/results_controller.rb | 2 +-
app/controllers/steps_controller.rb | 2 +-
app/jobs/protocols/docx_import_job.rb | 2 +-
app/models/asset.rb | 5 +++--
app/models/concerns/versioned_attachments.rb | 19 +++++++++++++++++++
app/models/repository_asset_value.rb | 8 ++++----
.../save_pdf_to_inventory_item.rb | 2 +-
app/services/team_importer.rb | 2 +-
.../protocol_importers/attachments_builder.rb | 2 +-
app/utilities/protocols_importer.rb | 2 +-
app/utilities/protocols_importer_v2.rb | 2 +-
15 files changed, 39 insertions(+), 19 deletions(-)
create mode 100644 app/models/concerns/versioned_attachments.rb
diff --git a/app/controllers/api/v1/results_controller.rb b/app/controllers/api/v1/results_controller.rb
index c26c2ef02..4665f46a8 100644
--- a/app/controllers/api/v1/results_controller.rb
+++ b/app/controllers/api/v1/results_controller.rb
@@ -124,7 +124,7 @@ module Api
Result.transaction do
old_checksum = asset.file.blob.checksum
if @form_multipart_upload
- asset.file.attach(result_file_params[:file])
+ asset.attach_file_version(result_file_params[:file])
else
blob = create_blob_from_params
asset.update!(file: blob)
diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb
index 54c6e7440..ae8d0e126 100644
--- a/app/controllers/asset_sync_controller.rb
+++ b/app/controllers/asset_sync_controller.rb
@@ -45,7 +45,7 @@ class AssetSyncController < ApplicationController
if wopi_file?(@asset)
@asset.update_contents(request.body)
else
- @asset.file.attach(io: request.body, filename: @asset.file.filename)
+ @asset.attach_file_version(io: request.body, filename: @asset.file.filename)
@asset.touch
end
@@ -94,7 +94,7 @@ class AssetSyncController < ApplicationController
metadata: @asset.blob.metadata
)
- new_asset.file.attach(blob)
+ new_asset.attach_file_version(blob)
case @asset.parent
when Step
diff --git a/app/controllers/gene_sequence_assets_controller.rb b/app/controllers/gene_sequence_assets_controller.rb
index a706a200f..d18cb72c7 100644
--- a/app/controllers/gene_sequence_assets_controller.rb
+++ b/app/controllers/gene_sequence_assets_controller.rb
@@ -75,7 +75,7 @@ class GeneSequenceAssetsController < ApplicationController
@asset.file.purge
@asset.preview_image.purge
- @asset.file.attach(
+ @asset.attach_file_version(
io: StringIO.new(params[:sequence_data].to_json),
filename: "#{params[:sequence_name]}.json"
)
diff --git a/app/controllers/result_assets_controller.rb b/app/controllers/result_assets_controller.rb
index e2c429260..400ae671e 100644
--- a/app/controllers/result_assets_controller.rb
+++ b/app/controllers/result_assets_controller.rb
@@ -125,7 +125,7 @@ class ResultAssetsController < ApplicationController
ActiveRecord::Base.transaction do
params[:results_files].each do |index, file|
asset = Asset.create!(created_by: current_user, last_modified_by: current_user, team: current_team)
- asset.file.attach(file[:signed_blob_id])
+ asset.attach_file_version(file[:signed_blob_id])
result = Result.create!(user: current_user,
my_module: @my_module,
name: params[:results_names][index],
diff --git a/app/controllers/results_controller.rb b/app/controllers/results_controller.rb
index 075b2b669..3bc46e3d2 100644
--- a/app/controllers/results_controller.rb
+++ b/app/controllers/results_controller.rb
@@ -90,7 +90,7 @@ class ResultsController < ApplicationController
team: @my_module.team,
view_mode: @result.assets_view_mode
)
- @asset.file.attach(params[:signed_blob_id])
+ @asset.attach_file_version(params[:signed_blob_id])
@asset.post_process_file
end
diff --git a/app/controllers/steps_controller.rb b/app/controllers/steps_controller.rb
index 40f2845f5..ce97a4cc2 100644
--- a/app/controllers/steps_controller.rb
+++ b/app/controllers/steps_controller.rb
@@ -41,7 +41,7 @@ class StepsController < ApplicationController
team: @protocol.team,
view_mode: @step.assets_view_mode
)
- @asset.file.attach(params[:signed_blob_id])
+ @asset.attach_file_version(params[:signed_blob_id])
@asset.post_process_file
default_message_items = {
diff --git a/app/jobs/protocols/docx_import_job.rb b/app/jobs/protocols/docx_import_job.rb
index 49a34bbc5..dccd1a0dd 100644
--- a/app/jobs/protocols/docx_import_job.rb
+++ b/app/jobs/protocols/docx_import_job.rb
@@ -117,7 +117,7 @@ module Protocols
def create_step_asset_element!(step, step_element_json)
asset = @team.assets.new(created_by: @user, last_modified_by: @user)
# Decode the file bytes
- asset.file.attach(io: StringIO.new(Base64.decode64(step_element_json['contents'])), filename: 'file.blob')
+ asset.attach_file_version(io: StringIO.new(Base64.decode64(step_element_json['contents'])), filename: 'file.blob')
asset.save!
step.step_assets.create!(asset: asset)
asset.post_process_file
diff --git a/app/models/asset.rb b/app/models/asset.rb
index 0c2601d82..9e0745642 100644
--- a/app/models/asset.rb
+++ b/app/models/asset.rb
@@ -8,6 +8,7 @@ class Asset < ApplicationRecord
include ActiveStorageFileUtil
include ActiveStorageConcerns
include ActiveStorageHelper
+ include VersionedAttachments
require 'tempfile'
# Lock duration set to 30 minutes
@@ -17,7 +18,7 @@ class Asset < ApplicationRecord
enum view_mode: { thumbnail: 0, list: 1, inline: 2 }
# ActiveStorage configuration
- has_one_attached :file
+ has_one_versioned_attached :file
has_one_attached :file_pdf_preview
has_one_attached :preview_image
@@ -166,7 +167,7 @@ class Asset < ApplicationRecord
filename: blob.filename,
metadata: blob.metadata
)
- to_asset.file.attach(to_blob)
+ to_asset.attach_file_version(to_blob)
end
if preview_image.attached?
diff --git a/app/models/concerns/versioned_attachments.rb b/app/models/concerns/versioned_attachments.rb
new file mode 100644
index 000000000..464ff1aff
--- /dev/null
+++ b/app/models/concerns/versioned_attachments.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module VersionedAttachments
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def has_one_versioned_attached(name)
+ has_one_attached name, dependent: :detach
+ has_many_attached "previous_#{name.to_s.pluralize}", dependent: :detach
+
+ define_method "attach_#{name}_version" do |*args, **options|
+ ActiveRecord::Base.transaction(requires_new: true) do
+ __send__("previous_#{name.to_s.pluralize}").attach(__send__(name).blob) if __send__(name).attached?
+ __send__(name).attach(*args, **options)
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/repository_asset_value.rb b/app/models/repository_asset_value.rb
index 5e9ba015f..9e4685aa6 100644
--- a/app/models/repository_asset_value.rb
+++ b/app/models/repository_asset_value.rb
@@ -60,9 +60,9 @@ class RepositoryAssetValue < ApplicationRecord
def update_data!(new_data, user)
if new_data.is_a?(String) # assume it's a signed_id_token
- asset.file.attach(new_data)
+ asset.attach_file_version(new_data)
elsif new_data[:file_data]
- asset.file.attach(io: StringIO.new(Base64.decode64(new_data[:file_data])), filename: new_data[:file_name])
+ asset.attach_file_version(io: StringIO.new(Base64.decode64(new_data[:file_data])), filename: new_data[:file_name])
end
asset.file_pdf_preview.purge if asset.file_pdf_preview.attached?
@@ -99,9 +99,9 @@ class RepositoryAssetValue < ApplicationRecord
value.asset = Asset.create!(created_by: value.created_by, last_modified_by: value.created_by, team: team)
if payload.is_a?(String) # assume it's a signed_id_token
- value.asset.file.attach(payload)
+ value.asset.attach_file_version(payload)
elsif payload[:file_data]
- value.asset.file.attach(io: StringIO.new(Base64.decode64(payload[:file_data])), filename: payload[:file_name])
+ value.asset.attach_file_version(io: StringIO.new(Base64.decode64(payload[:file_data])), filename: payload[:file_name])
end
value.asset.post_process_file
diff --git a/app/services/report_actions/save_pdf_to_inventory_item.rb b/app/services/report_actions/save_pdf_to_inventory_item.rb
index 88b1e1a90..01866820f 100644
--- a/app/services/report_actions/save_pdf_to_inventory_item.rb
+++ b/app/services/report_actions/save_pdf_to_inventory_item.rb
@@ -44,7 +44,7 @@ module ReportActions
def create_new_asset
asset = Asset.create(created_by: @user, last_modified_by: @user, team: @team)
- asset.file.attach(@report.pdf_file.blob)
+ asset.attach_file_version(@report.pdf_file.blob)
asset
end
diff --git a/app/services/team_importer.rb b/app/services/team_importer.rb
index e600b451e..e81c651c6 100644
--- a/app/services/team_importer.rb
+++ b/app/services/team_importer.rb
@@ -934,7 +934,7 @@ class TeamImporter
user_id || find_user(asset.last_modified_by_id)
asset.team = team
asset.save!
- asset.file.attach(io: file, filename: File.basename(file))
+ asset.attach_file_version(io: file, filename: File.basename(file))
asset.post_process_file
@asset_mappings[orig_asset_id] = asset.id
@asset_counter += 1
diff --git a/app/utilities/protocol_importers/attachments_builder.rb b/app/utilities/protocol_importers/attachments_builder.rb
index df6788f1d..dd2bd4799 100644
--- a/app/utilities/protocol_importers/attachments_builder.rb
+++ b/app/utilities/protocol_importers/attachments_builder.rb
@@ -7,7 +7,7 @@ module ProtocolImporters
step_json[:attachments].map do |f|
asset = Asset.new(created_by: user, last_modified_by: user, team: team)
- asset.file.attach(io: URI.open(f[:url]), filename: f[:name])
+ asset.attach_file_version(io: URI.open(f[:url]), filename: f[:name])
asset
end
end
diff --git a/app/utilities/protocols_importer.rb b/app/utilities/protocols_importer.rb
index a66b8fe02..4738c8eb9 100644
--- a/app/utilities/protocols_importer.rb
+++ b/app/utilities/protocols_importer.rb
@@ -132,7 +132,7 @@ class ProtocolsImporter
)
# Decode the file bytes
- asset.file.attach(io: StringIO.new(Base64.decode64(asset_json['bytes'])),
+ asset.attach_file_version(io: StringIO.new(Base64.decode64(asset_json['bytes'])),
filename: asset_json['fileName'],
content_type: asset_json['fileType'],
metadata: JSON.parse(asset_json['fileMetadata'] || '{}'))
diff --git a/app/utilities/protocols_importer_v2.rb b/app/utilities/protocols_importer_v2.rb
index ba6e3b813..9d91f438c 100644
--- a/app/utilities/protocols_importer_v2.rb
+++ b/app/utilities/protocols_importer_v2.rb
@@ -109,7 +109,7 @@ class ProtocolsImporterV2
)
# Decode the file bytes
- asset.file.attach(io: StringIO.new(Base64.decode64(asset_json['bytes'])),
+ asset.attach_file_version(io: StringIO.new(Base64.decode64(asset_json['bytes'])),
filename: asset_json['fileName'],
content_type: asset_json['fileType'],
metadata: JSON.parse(asset_json['fileMetadata'] || '{}'))
From 157a23d025a36d9538e67c7da562218f6823f23e Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Mon, 16 Sep 2024 11:42:29 +0200
Subject: [PATCH 19/96] Fix viewable scope for sharable models [SCI-11057]
---
app/models/concerns/shareable.rb | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/app/models/concerns/shareable.rb b/app/models/concerns/shareable.rb
index 6f157766e..3f94a0770 100644
--- a/app/models/concerns/shareable.rb
+++ b/app/models/concerns/shareable.rb
@@ -30,18 +30,17 @@ module Shareable
readable = readable_by_user(user).left_outer_joins(:team_shared_objects)
readable
.where(team: teams)
- .or(where(team_shared_objects: { team: teams }))
- .or(where(if column_names.include?('permission_level')
- {
- permission_level: [
- Extends::SHARED_OBJECTS_PERMISSION_LEVELS[:shared_read],
- Extends::SHARED_OBJECTS_PERMISSION_LEVELS[:shared_write]
- ]
- }
- else
- {}
- end
- ).where.not(team: teams))
+ .or(model.where(team_shared_objects: { team: teams }))
+ .or(model.where(if column_names.include?('permission_level')
+ {
+ permission_level: [
+ Extends::SHARED_OBJECTS_PERMISSION_LEVELS[:shared_read],
+ Extends::SHARED_OBJECTS_PERMISSION_LEVELS[:shared_write]
+ ]
+ }
+ else
+ {}
+ end).where.not(team: teams))
.distinct
}
rescue ActiveRecord::NoDatabaseError,
From 444b561060b8a71387c4221cc60bf305b259015d Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Tue, 17 Sep 2024 15:19:44 +0200
Subject: [PATCH 20/96] Implement file versions modal [SCI-11039]
---
app/controllers/assets_controller.rb | 16 +++--
.../content/attachments/context_menu.vue | 17 ++++-
.../vue/shared/file_versions_modal.vue | 66 +++++++++++++++++++
app/models/concerns/versioned_attachments.rb | 16 ++++-
app/serializers/asset_serializer.rb | 3 +-
config/locales/en.yml | 7 ++
config/routes.rb | 1 +
7 files changed, 118 insertions(+), 8 deletions(-)
create mode 100644 app/javascript/vue/shared/file_versions_modal.vue
diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb
index 383964890..314583de4 100644
--- a/app/controllers/assets_controller.rb
+++ b/app/controllers/assets_controller.rb
@@ -197,7 +197,7 @@ class AssetsController < ApplicationController
return render_403 unless can_read_team?(@asset.team)
@asset.last_modified_by = current_user
- @asset.file.attach(io: params.require(:image), filename: orig_file_name)
+ @asset.attach_file_version(io: params.require(:image), filename: orig_file_name, current_user: current_user)
@asset.save!
create_edit_image_activity(@asset, current_user, :finish_editing)
# release previous image space
@@ -242,9 +242,10 @@ class AssetsController < ApplicationController
# Asset validation
asset = Asset.new(created_by: current_user, team: current_team)
- asset.file.attach(io: StringIO.new,
- filename: "#{params[:file_name]}.#{params[:file_type]}",
- content_type: wopi_content_type(params[:file_type]))
+ asset.attach_file_version(io: StringIO.new,
+ filename: "#{params[:file_name]}.#{params[:file_type]}",
+ content_type: wopi_content_type(params[:file_type]),
+ current_user: current_user)
unless asset.valid?(:wopi_file_creation)
render json: {
@@ -397,6 +398,13 @@ class AssetsController < ApplicationController
render json: { checksum: @asset.file.blob.checksum }
end
+ def versions
+ render(
+ json: [@asset.file.blob] +
+ @asset.previous_files.map(&:blob).sort_by { |b| -1 * b.metadata['version'].to_i }
+ )
+ end
+
private
def load_vars
diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue
index bb17af66c..5f9a6a7bb 100644
--- a/app/javascript/vue/shared/content/attachments/context_menu.vue
+++ b/app/javascript/vue/shared/content/attachments/context_menu.vue
@@ -34,6 +34,7 @@
@duplicate="duplicate"
@viewMode="changeViewMode"
@move="showMoveModal"
+ @fileVersionsModal="fileVersionsModal = true"
@menu-toggle="$emit('menu-toggle', $event)"
>
@@ -55,6 +56,11 @@
:targets_url="attachment.attributes.urls.move_targets"
@confirm="moveAttachment($event)" @cancel="closeMoveModal"
/>
+
@@ -65,6 +71,7 @@ import deleteAttachmentModal from './delete_modal.vue';
import MoveAssetModal from '../modal/move.vue';
import MoveMixin from './mixins/move.js';
import MenuDropdown from '../../menu_dropdown.vue';
+import FileVersionsModal from '../../file_versions_modal.vue';
import axios from '../../../../packs/custom_axios.js';
export default {
@@ -73,6 +80,7 @@ export default {
RenameAttachmentModal,
deleteAttachmentModal,
MoveAssetModal,
+ FileVersionsModal,
MenuDropdown
},
mixins: [MoveMixin],
@@ -91,7 +99,8 @@ export default {
return {
viewModeOptions: ['inline', 'thumbnail', 'list'],
deleteModal: false,
- renameModal: false
+ renameModal: false,
+ fileVersionsModal: false
};
},
computed: {
@@ -136,6 +145,12 @@ export default {
});
});
}
+ if (this.attachment.attributes.urls.versions) {
+ menu.push({
+ text: this.i18n.t('assets.context_menu.versions'),
+ emit: 'fileVersionsModal'
+ });
+ }
return menu;
}
},
diff --git a/app/javascript/vue/shared/file_versions_modal.vue b/app/javascript/vue/shared/file_versions_modal.vue
new file mode 100644
index 000000000..0aeb81b43
--- /dev/null
+++ b/app/javascript/vue/shared/file_versions_modal.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
v{{ fileVersion.attributes.version }}
+
{{ fileVersion.attributes.filename }}
+
+ ({{ i18n.t("assets.file_versions_modal.restored_from_version", { version: fileVersion.attributes.restored_from_version }) }})
+
+
+
+
{{ fileVersion.attributes.created_at }}
+
{{ fileVersion.attributes.created_by.full_name }}
+
{{ (fileVersion.attributes.byte_size/1024).toFixed(1) }}KB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/models/concerns/versioned_attachments.rb b/app/models/concerns/versioned_attachments.rb
index 464ff1aff..6a32e6963 100644
--- a/app/models/concerns/versioned_attachments.rb
+++ b/app/models/concerns/versioned_attachments.rb
@@ -8,10 +8,22 @@ module VersionedAttachments
has_one_attached name, dependent: :detach
has_many_attached "previous_#{name.to_s.pluralize}", dependent: :detach
- define_method "attach_#{name}_version" do |*args, **options|
+ define_method :"attach_#{name}_version" do |*args, **options|
ActiveRecord::Base.transaction(requires_new: true) do
- __send__("previous_#{name.to_s.pluralize}").attach(__send__(name).blob) if __send__(name).attached?
+ __send__(:"previous_#{name.to_s.pluralize}").attach(__send__(name).blob) if __send__(name).attached?
__send__(name).attach(*args, **options)
+
+ new_blob = __send__(name).blob
+ new_blob.metadata['created_by_id'] = last_modified_by_id
+ new_blob.save!
+
+ # set version of current latest file if previous versions exist
+ next unless __send__(:"previous_#{name.to_s.pluralize}").any?
+
+ new_version =
+ (__send__(:"previous_#{name.to_s.pluralize}").last.blob.metadata['version'] || 1) + 1
+ new_blob.metadata['version'] = new_version
+ new_blob.save!
end
end
end
diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb
index 9817f448a..ba4fa56ef 100644
--- a/app/serializers/asset_serializer.rb
+++ b/app/serializers/asset_serializer.rb
@@ -138,7 +138,8 @@ class AssetSerializer < ActiveModel::Serializer
load_asset: load_asset_path(object),
asset_file: asset_file_url_path(object),
marvin_js: marvin_js_asset_path(object),
- marvin_js_icon: image_path('icon_small/marvinjs.svg')
+ marvin_js_icon: image_path('icon_small/marvinjs.svg'),
+ versions: (asset_versions_path(object) if attached)
}
user = scope[:user] || @instance_options[:user]
if can_manage_asset?(user, object)
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 4b046bb51..78daf6634 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -4005,6 +4005,13 @@ en:
inline_html: "Large"
thumbnail_html: "Thumbnail"
list_html: "List"
+ versions: "Versions"
+ file_versions_modal:
+ title: "Version history"
+ download: "Download"
+ restore: "Restore"
+ size: "Size"
+ restored_from_version: "restored from v%{version}"
rename_modal:
title: "Rename file"
min_length_error: "File name must be at least 1 character long."
diff --git a/config/routes.rb b/config/routes.rb
index 3c2d9a9ae..3358bd239 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -861,6 +861,7 @@ Rails.application.routes.draw do
get 'files/:id/edit', to: 'assets#edit', as: 'edit_asset'
get 'files/:id/checksum', to: 'assets#checksum', as: 'asset_checksum'
get 'files/:id/show', to: 'assets#show', as: 'asset_show'
+ get 'files/:id/versions', to: 'assets#versions', as: 'asset_versions'
patch 'files/:id/toggle_view_mode', to: 'assets#toggle_view_mode', as: 'toggle_view_mode'
get 'files/:id/load_asset', to: 'assets#load_asset', as: 'load_asset'
post 'files/:id/update_image', to: 'assets#update_image',
From 48fb68c07ce6f147b259c545249e9a684084fcfe Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Tue, 17 Sep 2024 16:26:45 +0200
Subject: [PATCH 21/96] Implement restore functionality in file versions modal
[SCI-11042]
---
app/controllers/assets_controller.rb | 7 +++++-
.../attachments/attachment_actions.vue | 1 +
.../content/attachments/context_menu.vue | 4 ++-
.../vue/shared/content/attachments/inline.vue | 1 +
.../vue/shared/content/attachments/list.vue | 1 +
.../shared/content/attachments/thumbnail.vue | 1 +
.../vue/shared/file_versions_modal.vue | 25 +++++++++++++++----
app/models/concerns/versioned_attachments.rb | 18 +++++++++++++
app/serializers/asset_serializer.rb | 3 ++-
config/routes.rb | 1 +
10 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb
index 314583de4..5fded7712 100644
--- a/app/controllers/assets_controller.rb
+++ b/app/controllers/assets_controller.rb
@@ -197,7 +197,7 @@ class AssetsController < ApplicationController
return render_403 unless can_read_team?(@asset.team)
@asset.last_modified_by = current_user
- @asset.attach_file_version(io: params.require(:image), filename: orig_file_name, current_user: current_user)
+ @asset.attach_file_version(io: params.require(:image), filename: orig_file_name)
@asset.save!
create_edit_image_activity(@asset, current_user, :finish_editing)
# release previous image space
@@ -405,6 +405,11 @@ class AssetsController < ApplicationController
)
end
+ def restore_version
+ @asset.restore_file_version(params[:version].to_i)
+ render json: @asset.file.blob
+ end
+
private
def load_vars
diff --git a/app/javascript/vue/shared/content/attachments/attachment_actions.vue b/app/javascript/vue/shared/content/attachments/attachment_actions.vue
index 71561f7c3..6147efa33 100644
--- a/app/javascript/vue/shared/content/attachments/attachment_actions.vue
+++ b/app/javascript/vue/shared/content/attachments/attachment_actions.vue
@@ -27,6 +27,7 @@
@attachment:changed="$emit('attachment:changed', $event)"
@attachment:update="$emit('attachment:update', $event)"
@menu-toggle="$emit('attachment:toggle_menu', $event)"
+ @attachment:versionRestored="$emit('attachment:versionRestored', $event)"
:withBorder="withBorder"
/>
diff --git a/app/javascript/vue/shared/content/attachments/context_menu.vue b/app/javascript/vue/shared/content/attachments/context_menu.vue
index 5f9a6a7bb..8d7d67c6d 100644
--- a/app/javascript/vue/shared/content/attachments/context_menu.vue
+++ b/app/javascript/vue/shared/content/attachments/context_menu.vue
@@ -58,8 +58,10 @@
/>
diff --git a/app/javascript/vue/shared/content/attachments/inline.vue b/app/javascript/vue/shared/content/attachments/inline.vue
index 14788fc32..d1fec5fb7 100644
--- a/app/javascript/vue/shared/content/attachments/inline.vue
+++ b/app/javascript/vue/shared/content/attachments/inline.vue
@@ -38,6 +38,7 @@
@attachment:delete="deleteAttachment"
@attachment:moved="attachmentMoved"
@attachment:uploaded="reloadAttachments"
+ @attachment:versionRestored="reloadAttachments"
@attachment:changed="$emit('attachment:changed', $event)"
@attachment:update="$emit('attachment:update', $event)"
@attachment:toggle_menu="toggleMenuDropdown"
diff --git a/app/javascript/vue/shared/content/attachments/list.vue b/app/javascript/vue/shared/content/attachments/list.vue
index d8cdc5ad6..2a2aeb03b 100644
--- a/app/javascript/vue/shared/content/attachments/list.vue
+++ b/app/javascript/vue/shared/content/attachments/list.vue
@@ -37,6 +37,7 @@
@attachment:delete="deleteAttachment"
@attachment:moved="attachmentMoved"
@attachment:uploaded="reloadAttachments"
+ @attachment:versionRestored="reloadAttachments"
@attachment:changed="$emit('attachment:changed', $event)"
@attachment:update="$emit('attachment:update', $event)"
@attachment:toggle_menu="toggleMenuDropdown"
diff --git a/app/javascript/vue/shared/content/attachments/thumbnail.vue b/app/javascript/vue/shared/content/attachments/thumbnail.vue
index ebdc25442..bc7ac5684 100644
--- a/app/javascript/vue/shared/content/attachments/thumbnail.vue
+++ b/app/javascript/vue/shared/content/attachments/thumbnail.vue
@@ -54,6 +54,7 @@
@attachment:delete="deleteAttachment"
@attachment:moved="attachmentMoved"
@attachment:uploaded="reloadAttachments"
+ @attachment:versionRestored="reloadAttachments"
@attachment:changed="$emit('attachment:changed', $event)"
@attachment:update="$emit('attachment:update', $event)"
@attachment:toggle_menu="toggleMenu"
diff --git a/app/javascript/vue/shared/file_versions_modal.vue b/app/javascript/vue/shared/file_versions_modal.vue
index 0aeb81b43..47c8ffd7a 100644
--- a/app/javascript/vue/shared/file_versions_modal.vue
+++ b/app/javascript/vue/shared/file_versions_modal.vue
@@ -28,7 +28,7 @@
@@ -46,7 +46,11 @@ import axios from '../../packs/custom_axios';
export default {
name: 'FileVersionsModal',
props: {
- url: {
+ versionsUrl: {
+ type: String,
+ required: true
+ },
+ restoreVersionUrl: {
type: String,
required: true
}
@@ -58,9 +62,20 @@ export default {
};
},
created() {
- axios.get(this.url).then((response) => {
- this.fileVersions = response.data.data;
- });
+ this.loadVersions();
+ },
+ methods: {
+ loadVersions() {
+ axios.get(this.versionsUrl).then((response) => {
+ this.fileVersions = response.data.data;
+ });
+ },
+ restoreVersion(version) {
+ axios.post(this.restoreVersionUrl, { version: version }).then(() => {
+ this.loadVersions();
+ this.$emit('fileVersionRestored');
+ });
+ }
}
};
diff --git a/app/models/concerns/versioned_attachments.rb b/app/models/concerns/versioned_attachments.rb
index 6a32e6963..77159a023 100644
--- a/app/models/concerns/versioned_attachments.rb
+++ b/app/models/concerns/versioned_attachments.rb
@@ -26,6 +26,24 @@ module VersionedAttachments
new_blob.save!
end
end
+
+ define_method :"restore_#{name}_version" do |version|
+ ActiveRecord::Base.transaction(requires_new: true) do
+ blob = __send__(:"previous_#{name.to_s.pluralize}").map(&:blob).find do |b|
+ (b.metadata['version'] || 1) == version
+ end
+
+ blob.open do |tmp_file|
+ new_blob = ActiveStorage::Blob.create_and_upload!(
+ io: tmp_file,
+ filename: blob.filename,
+ metadata: blob.metadata.merge({ 'restored_from_version' => version })
+ )
+
+ __send__(:"attach_#{name}_version", new_blob)
+ end
+ end
+ end
end
end
end
diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb
index ba4fa56ef..51abd6204 100644
--- a/app/serializers/asset_serializer.rb
+++ b/app/serializers/asset_serializer.rb
@@ -152,7 +152,8 @@ class AssetSerializer < ActiveModel::Serializer
duplicate: asset_duplicate_path(object),
move_targets: asset_move_tagets_path(object),
move: asset_move_path(object),
- rename: asset_rename_path(object)
+ rename: asset_rename_path(object),
+ restore_version: asset_restore_version_path(object)
)
end
diff --git a/config/routes.rb b/config/routes.rb
index 3358bd239..bdd085d7e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -862,6 +862,7 @@ Rails.application.routes.draw do
get 'files/:id/checksum', to: 'assets#checksum', as: 'asset_checksum'
get 'files/:id/show', to: 'assets#show', as: 'asset_show'
get 'files/:id/versions', to: 'assets#versions', as: 'asset_versions'
+ post 'files/:id/restore_version', to: 'assets#restore_version', as: 'asset_restore_version'
patch 'files/:id/toggle_view_mode', to: 'assets#toggle_view_mode', as: 'toggle_view_mode'
get 'files/:id/load_asset', to: 'assets#load_asset', as: 'load_asset'
post 'files/:id/update_image', to: 'assets#update_image',
From 9aa43f4c36a800b0e4e714a19e3ce02f0d1f2500 Mon Sep 17 00:00:00 2001
From: Martin Artnik <85488244+artoscinote@users.noreply.github.com>
Date: Wed, 18 Sep 2024 13:36:49 +0200
Subject: [PATCH 22/96] Add restore file permission check [SCI-11042]
---
app/controllers/assets_controller.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb
index 5fded7712..c4a93ef29 100644
--- a/app/controllers/assets_controller.rb
+++ b/app/controllers/assets_controller.rb
@@ -18,7 +18,7 @@ class AssetsController < ApplicationController
before_action :load_vars, except: :create_wopi_file
before_action :check_read_permission, except: %i(edit destroy duplicate create_wopi_file toggle_view_mode)
- before_action :check_manage_permission, only: %i(edit destroy duplicate rename toggle_view_mode)
+ before_action :check_manage_permission, only: %i(edit destroy duplicate rename toggle_view_mode restore_version)
def file_preview
editable = can_manage_asset?(@asset) && (@asset.repository_asset_value.blank? ||
From 6c2c416bbffebb51d38af3452c2ed5329ae7b075 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Wed, 18 Sep 2024 13:51:03 +0200
Subject: [PATCH 23/96] Implement disabled file versioning state [SCI-11040]
---
app/assets/stylesheets/themes/scinote.scss | 4 +
app/controllers/assets_controller.rb | 14 ++-
.../vue/shared/file_versions_modal.vue | 90 +++++++++++++++----
app/models/concerns/versioned_attachments.rb | 6 ++
app/serializers/asset_serializer.rb | 4 +-
config/locales/en.yml | 5 +-
6 files changed, 99 insertions(+), 24 deletions(-)
diff --git a/app/assets/stylesheets/themes/scinote.scss b/app/assets/stylesheets/themes/scinote.scss
index 711677980..fd7f60180 100644
--- a/app/assets/stylesheets/themes/scinote.scss
+++ b/app/assets/stylesheets/themes/scinote.scss
@@ -1362,6 +1362,10 @@ th.custom-field .modal-tooltiptext {
cursor: pointer;
}
+.tooltip {
+ z-index: 9999;
+}
+
.tooltip-open {
background-color: $color-concrete;
color: $color-black;
diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb
index c4a93ef29..dfa46e7fe 100644
--- a/app/controllers/assets_controller.rb
+++ b/app/controllers/assets_controller.rb
@@ -399,13 +399,23 @@ class AssetsController < ApplicationController
end
def versions
+ blobs =
+ [@asset.file.blob] +
+ @asset.previous_files.map(&:blob).sort_by { |b| -1 * b.metadata['version'].to_i }[0..(VersionedAttachments.enabled? ? -1 : 1)]
render(
- json: [@asset.file.blob] +
- @asset.previous_files.map(&:blob).sort_by { |b| -1 * b.metadata['version'].to_i }
+ json: ActiveModel::SerializableResource.new(
+ blobs,
+ each_serializer: ActiveStorage::BlobSerializer
+ ).as_json.merge(
+ enabled: VersionedAttachments.enabled?,
+ enable_url: ENV.fetch('SCINOTE_FILE_VERSIONING_ENABLE_URL', nil)
+ )
)
end
def restore_version
+ render_403 unless VersionedAttachments.enabled?
+
@asset.restore_file_version(params[:version].to_i)
render json: @asset.file.blob
end
diff --git a/app/javascript/vue/shared/file_versions_modal.vue b/app/javascript/vue/shared/file_versions_modal.vue
index 47c8ffd7a..63d12c456 100644
--- a/app/javascript/vue/shared/file_versions_modal.vue
+++ b/app/javascript/vue/shared/file_versions_modal.vue
@@ -9,30 +9,68 @@
-
-
-
-
-
v{{ fileVersion.attributes.version }}
-
{{ fileVersion.attributes.filename }}
-
- ({{ i18n.t("assets.file_versions_modal.restored_from_version", { version: fileVersion.attributes.restored_from_version }) }})
-
+
+
+
+
+
+
+ {{ i18n.t("assets.file_versions_modal.original_file") }}
+
+
v{{ fileVersion.attributes.version }}
+
{{ fileVersion.attributes.filename }}
+
+ ({{ i18n.t("assets.file_versions_modal.restored_from_version", { version: fileVersion.attributes.restored_from_version }) }})
+
+
+
+
{{ fileVersion.attributes.created_at }}
+
{{ fileVersion.attributes.created_by.full_name }}
+
{{ Math.round(fileVersion.attributes.byte_size/1024) }}KB
+
-
-
{{ fileVersion.attributes.created_at }}
-
{{ fileVersion.attributes.created_by.full_name }}
-
{{ (fileVersion.attributes.byte_size/1024).toFixed(1) }}KB
-
-
-
+
+
+
+
+
+
+
{{ i18n.t('assets.file_versions_modal.title') }}
+ {{ i18n.t('assets.file_versions_modal.disabled_disclaimer') }}
+
+
+
+
@@ -58,16 +96,30 @@ export default {
mixins: [modalMixin],
data() {
return {
- fileVersions: null
+ fileVersions: null,
+ enabled: null,
+ enableUrl: null
};
},
created() {
this.loadVersions();
},
+ beforeUnmount() {
+ document.querySelectorAll('[data-render-tooltip]').forEach((e) => {
+ window.destroyTooltip(e);
+ });
+ },
methods: {
loadVersions() {
axios.get(this.versionsUrl).then((response) => {
this.fileVersions = response.data.data;
+ this.enabled = response.data.enabled;
+ this.enableUrl = response.data.enable_url;
+ this.$nextTick(() => {
+ document.querySelectorAll('[data-render-tooltip]').forEach((e) => {
+ window.initTooltip(e);
+ });
+ });
});
},
restoreVersion(version) {
diff --git a/app/models/concerns/versioned_attachments.rb b/app/models/concerns/versioned_attachments.rb
index 77159a023..6adc4d809 100644
--- a/app/models/concerns/versioned_attachments.rb
+++ b/app/models/concerns/versioned_attachments.rb
@@ -46,4 +46,10 @@ module VersionedAttachments
end
end
end
+
+ module_function
+
+ def enabled?
+ ApplicationSettings.instance.values['storage_locations_enabled']
+ end
end
diff --git a/app/serializers/asset_serializer.rb b/app/serializers/asset_serializer.rb
index 51abd6204..53c31236d 100644
--- a/app/serializers/asset_serializer.rb
+++ b/app/serializers/asset_serializer.rb
@@ -152,11 +152,11 @@ class AssetSerializer < ActiveModel::Serializer
duplicate: asset_duplicate_path(object),
move_targets: asset_move_tagets_path(object),
move: asset_move_path(object),
- rename: asset_rename_path(object),
- restore_version: asset_restore_version_path(object)
+ rename: asset_rename_path(object)
)
end
+ urls[:restore_version] = asset_restore_version_path(object) if VersionedAttachments.enabled?
urls[:open_vector_editor_edit] = edit_gene_sequence_asset_path(object.id) if can_manage_asset?(user, object)
if can_manage_asset?(user, object) && can_open_asset_locally?(user, object)
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 78daf6634..a1e5ddc46 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -4009,9 +4009,12 @@ en:
file_versions_modal:
title: "Version history"
download: "Download"
- restore: "Restore"
+ restore: "Restore this version"
size: "Size"
restored_from_version: "restored from v%{version}"
+ original_file: "Original file"
+ enable_button: "Enable"
+ disabled_disclaimer: "This feature is currently disabled"
rename_modal:
title: "Rename file"
min_length_error: "File name must be at least 1 character long."
From 294eef13a2cae68bd99bb28c7776c7bac99cc775 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Wed, 18 Sep 2024 14:12:42 +0200
Subject: [PATCH 24/96] Fix file versioning disclamer load [SCI-11040]
---
app/javascript/vue/shared/file_versions_modal.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/javascript/vue/shared/file_versions_modal.vue b/app/javascript/vue/shared/file_versions_modal.vue
index 63d12c456..d1c893c4b 100644
--- a/app/javascript/vue/shared/file_versions_modal.vue
+++ b/app/javascript/vue/shared/file_versions_modal.vue
@@ -54,7 +54,7 @@
-
+
From 8bc8ccb2f7ccc3f903b1e26545ee3d68385488c1 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Wed, 18 Sep 2024 15:43:17 +0200
Subject: [PATCH 25/96] Improve rendering of docx tables [SCI-11056]
---
app/helpers/input_sanitize_helper.rb | 3 ++-
app/services/reports/docx_renderer.rb | 7 +++++
.../reports/html_to_word_converter.rb | 27 ++++++++++++++++++-
3 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/app/helpers/input_sanitize_helper.rb b/app/helpers/input_sanitize_helper.rb
index e30a23666..7b479bbbd 100644
--- a/app/helpers/input_sanitize_helper.rb
+++ b/app/helpers/input_sanitize_helper.rb
@@ -40,11 +40,12 @@ module InputSanitizeHelper
preview_repository = options.fetch(:preview_repository, false)
format_opt = wrapper_tag.merge(sanitize: false)
base64_encoded_imgs = options.fetch(:base64_encoded_imgs, false)
- text = simple_format(text, {}, format_opt) if simple_f
# allow base64 images when sanitizing if base64_encoded_imgs is true
sanitizer_config = Constants::INPUT_SANITIZE_CONFIG.deep_dup
+
text = sanitize_input(text, tags, sanitizer_config: sanitizer_config)
+ text = simple_format(text, {}, format_opt) if simple_f
if text =~ SmartAnnotations::TagToHtml::USER_REGEX || text =~ SmartAnnotations::TagToHtml::REGEX
text = smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository)
diff --git a/app/services/reports/docx_renderer.rb b/app/services/reports/docx_renderer.rb
index 91872dc46..dd027bc4b 100644
--- a/app/services/reports/docx_renderer.rb
+++ b/app/services/reports/docx_renderer.rb
@@ -130,6 +130,13 @@ module Reports
row[:data].each do |cell|
docx_cell = Caracal::Core::Models::TableCellModel.new do |c|
cell.each do |content|
+ c.background content[:style][:background] if content.dig(:style, :background).present?
+ if content.dig(:style, :vertical_align).present? && content[:style][:vertical_align] != :middle
+ c.vertical_align content[:style][:vertical_align]
+ else
+ c.vertical_align :center
+ end
+
if content[:type] == 'p'
Reports::DocxRenderer.render_p_element(c, content, options.merge({ skip_br: true }))
elsif content[:type] == 'table'
diff --git a/app/services/reports/html_to_word_converter.rb b/app/services/reports/html_to_word_converter.rb
index f4e312f8e..07a0c0919 100644
--- a/app/services/reports/html_to_word_converter.rb
+++ b/app/services/reports/html_to_word_converter.rb
@@ -208,7 +208,7 @@ module Reports
if style
style_keys.each do |key|
- style_el = style.value.split(';').select { |i| (i.include? key) }[0]
+ style_el = style.value.split(';').find { |i| i.strip.start_with?(key) }
next unless style_el
value = style_el.split(':')[1].strip if style_el
@@ -259,6 +259,29 @@ module Reports
}
end
+ def table_cell_styling(elem)
+ style = elem.attributes['style']
+ result = {}
+ style_keys = %w(background-color vertical-align)
+
+ if style
+ style_keys.each do |key|
+ style_el = style.value.split(';').find { |i| (i.include? key) }
+ next unless style_el
+
+ value = style_el.split(':')[1].strip if style_el
+
+ case key
+ when 'background-color'
+ result[:background] = normalized_hex_color(value)
+ when 'vertical-align'
+ result[:vertical_align] = value.to_sym
+ end
+ end
+ end
+ result
+ end
+
def tiny_mce_table_element(table_element)
# array of elements
rows = table_element.css('tbody').first.children.map do |row|
@@ -267,11 +290,13 @@ module Reports
cells = row.children.map do |cell|
next unless cell.name == 'td'
+ style = table_cell_styling(cell)
# Parse cell content
formated_cell = recursive_children(cell.children, [], true)
# Combine text elements to single paragraph
formated_cell = combine_docx_elements(formated_cell)
+ formated_cell.each { |element| element[:style] = style } if style.present?
formated_cell
end.reject(&:blank?)
{ type: 'tr', data: cells }
From e53ea89f1409aa8fd591c7cb4f65af43537bff08 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Fri, 27 Sep 2024 16:03:05 +0200
Subject: [PATCH 26/96] Fix carcal version [SCI-11024]
---
Gemfile.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 4f4b947cf..bd0d3f156 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -24,7 +24,7 @@ GIT
GIT
remote: https://github.com/scinote-eln/caracal.git
- revision: f30bd2d26229c8118cc392c3a18409cb9a12ae02
+ revision: 7f5a653b23af51f38c9ecaf855fdffa6bc5427b2
branch: custom-docx-reports
specs:
caracal (1.4.2)
From a3d549495b2c73d73c808512ca5c33f8bcef9ef7 Mon Sep 17 00:00:00 2001
From: Andrej
Date: Tue, 1 Oct 2024 07:52:54 +0200
Subject: [PATCH 27/96] Fix adding backgroung color to docx tables [SCI-11119]
---
app/services/reports/html_to_word_converter.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/services/reports/html_to_word_converter.rb b/app/services/reports/html_to_word_converter.rb
index 07a0c0919..6d589a020 100644
--- a/app/services/reports/html_to_word_converter.rb
+++ b/app/services/reports/html_to_word_converter.rb
@@ -262,7 +262,7 @@ module Reports
def table_cell_styling(elem)
style = elem.attributes['style']
result = {}
- style_keys = %w(background-color vertical-align)
+ style_keys = %w(background-color vertical-align background)
if style
style_keys.each do |key|
@@ -272,7 +272,7 @@ module Reports
value = style_el.split(':')[1].strip if style_el
case key
- when 'background-color'
+ when 'background-color', 'background'
result[:background] = normalized_hex_color(value)
when 'vertical-align'
result[:vertical_align] = value.to_sym
From 1a04e249ba00e956ab3d023fcbebcd7d1b72039b Mon Sep 17 00:00:00 2001
From: Andrej
Date: Tue, 1 Oct 2024 11:07:12 +0200
Subject: [PATCH 28/96] Add support for inventory columns selection for docx
report [SCI-11095]
---
app/assets/javascripts/reports/new.js | 37 ++++++++++-
app/assets/stylesheets/reports/new.scss | 9 +++
app/models/my_module.rb | 16 ++---
app/models/report.rb | 12 +++-
.../reports/docx/draw_my_module_repository.rb | 3 +-
.../reports/docx/repository_helper.rb | 14 ++--
app/views/reports/wizard/_third_step.html.erb | 66 +++++++++++++------
config/locales/en.yml | 5 ++
8 files changed, 127 insertions(+), 35 deletions(-)
diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js
index 98023b3f0..bcc8ad5d3 100644
--- a/app/assets/javascripts/reports/new.js
+++ b/app/assets/javascripts/reports/new.js
@@ -968,6 +968,16 @@ function reportHandsonTableConverter() {
}
(function() {
+ function getSelectedRepositoryColumnValues(element, selectedAll = false) {
+ const values = [];
+ $(element).find('option').each((_, option) => {
+ if ($(option).attr('selected-value') || selectedAll) {
+ values.push(option.value);
+ }
+ });
+ return values;
+ }
+
function getReportData() {
var reportData = {};
@@ -1046,8 +1056,17 @@ function reportHandsonTableConverter() {
reportData.report.settings.task[e.value] = e.checked;
});
reportData.report.settings.task.repositories = [];
- $.each($('.task-contents-container .repositories-contents .repositories-setting:checked'), function(i, e) {
- reportData.report.settings.task.repositories.push(parseInt(e.value, 10));
+ reportData.report.settings.task.excluded_repository_columns = {};
+
+ $.each($('.task-contents-container .repositories-contents .repositories-setting:checked'), (_, e) => {
+ const value = parseInt(e.value, 10);
+ const $repositoryColumn = $(e).parent().siblings('.repository-columns')[0];
+ const selectedValues = dropdownSelector.getValues($repositoryColumn);
+ const excludedValues = getSelectedRepositoryColumnValues($repositoryColumn, true)
+ .filter((item) => !selectedValues.includes(item))
+ .map((el) => parseInt(el, 10));
+ reportData.report.settings.task.repositories.push(value);
+ reportData.report.settings.task.excluded_repository_columns[value] = excludedValues;
});
reportData.report.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder');
@@ -1359,6 +1378,20 @@ function reportHandsonTableConverter() {
if (dropdownSelector.getValues('#docxTemplateSelector').length > 0) {
loadDocxTemplate();
}
+
+ $('.repository-columns').each((_, element) => {
+ const elementId = `#${$(element).attr('id')}`;
+ const elements = getSelectedRepositoryColumnValues(elementId);
+
+ dropdownSelector.init(elementId, {
+ selectAppearance: 'simple',
+ optionClass: 'checkbox-icon'
+ });
+
+ if (elements.length) {
+ dropdownSelector.selectValues(elementId, elements);
+ }
+ });
}
function loadTemplate() {
diff --git a/app/assets/stylesheets/reports/new.scss b/app/assets/stylesheets/reports/new.scss
index b5258df6e..8b50742d8 100644
--- a/app/assets/stylesheets/reports/new.scss
+++ b/app/assets/stylesheets/reports/new.scss
@@ -260,6 +260,15 @@
}
// scss-lint:enable ImportantRule
+ .repositories-contents {
+ .dropdown-selector-container {
+ display: inline-flex;
+ flex-shrink: 0;
+ margin-left: auto;
+ width: 200px;
+ }
+ }
+
.project-selector-container {
background: $color-white;
box-shadow: $modal-shadow;
diff --git a/app/models/my_module.rb b/app/models/my_module.rb
index 36b7578ff..bca3c406e 100644
--- a/app/models/my_module.rb
+++ b/app/models/my_module.rb
@@ -391,17 +391,17 @@ class MyModule < ApplicationRecord
{ data: data, headers: headers }
end
- def repository_docx_json(repository)
- headers = [
- I18n.t('repositories.table.id'),
- I18n.t('repositories.table.row_name'),
- I18n.t('repositories.table.added_on'),
- I18n.t('repositories.table.added_by')
- ]
+ def repository_docx_json(repository, excluded_columns)
+ headers = Report.default_repository_columns.filter_map do |key, value|
+ value unless excluded_columns.include?(key.to_s.to_i)
+ end
+
custom_columns = []
return false unless repository
repository.repository_columns.order(:id).each do |column|
+ next if excluded_columns.include?(column.id)
+
if column.data_type == 'RepositoryStockValue'
if repository.has_stock_consumption?
headers.push(I18n.t('repositories.table.row_consumption'))
@@ -416,7 +416,7 @@ class MyModule < ApplicationRecord
records = repository.assigned_rows(self)
.select(:id, :name, :created_at, :created_by_id, :repository_id, :parent_id, :archived)
- { headers: headers, rows: records, custom_columns: custom_columns }
+ { headers: headers, rows: records, custom_columns: custom_columns, excluded_columns: excluded_columns }
end
def deep_clone(current_user)
diff --git a/app/models/report.rb b/app/models/report.rb
index 2d9a85908..61f092e33 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -64,7 +64,8 @@ class Report < ApplicationRecord
result_comments: true,
result_order: 'new',
activities: true,
- repositories: []
+ repositories: [],
+ excluded_repository_columns: {}
}
}.freeze
@@ -126,4 +127,13 @@ class Report < ApplicationRecord
ReportActions::ReportContent.new(report, content, {}, current_user).save_with_content
report
end
+
+ def self.default_repository_columns
+ {
+ '-1': I18n.t('repositories.table.id'),
+ '-2': I18n.t('repositories.table.row_name'),
+ '-3': I18n.t('repositories.table.added_on'),
+ '-4': I18n.t('repositories.table.added_by')
+ }
+ end
end
diff --git a/app/services/reports/docx/draw_my_module_repository.rb b/app/services/reports/docx/draw_my_module_repository.rb
index e6560c46e..a82b44b40 100644
--- a/app/services/reports/docx/draw_my_module_repository.rb
+++ b/app/services/reports/docx/draw_my_module_repository.rb
@@ -5,11 +5,12 @@ module Reports::Docx::DrawMyModuleRepository
my_module = subject.my_module
repository = subject.repository
repository = assigned_repository_or_snapshot(my_module, repository)
+ excluded_repository_columns = @settings.dig(:task, :excluded_repository_columns, repository.id.to_s) || {}
return unless repository && can_read_experiment?(@user, my_module.experiment) &&
(repository.is_a?(RepositorySnapshot) || can_read_repository?(@user, repository))
- repository_data = my_module.repository_docx_json(repository)
+ repository_data = my_module.repository_docx_json(repository, excluded_repository_columns)
return false unless repository_data[:rows].any? && can_read_repository?(@user, repository)
diff --git a/app/services/reports/docx/repository_helper.rb b/app/services/reports/docx/repository_helper.rb
index 50b693891..d962fd97d 100644
--- a/app/services/reports/docx/repository_helper.rb
+++ b/app/services/reports/docx/repository_helper.rb
@@ -6,12 +6,16 @@ module Reports::Docx::RepositoryHelper
def prepare_row_columns(repository_data, my_module = nil, repository = nil)
result = [repository_data[:headers]]
+ excluded_columns = repository_data[:excluded_columns]
+
repository_data[:rows].each do |record|
row = []
- row.push(record.code)
- row.push(escape_input(record.archived ? "#{record.name} [#{I18n.t('general.archived')}]" : record.name))
- row.push(I18n.l(record.created_at, format: :full))
- row.push(escape_input(record.created_by.full_name))
+ row.push(record.code) unless excluded_columns.include?(-1)
+ unless excluded_columns.include?(-2)
+ row.push(escape_input(record.archived ? "#{record.name} [#{I18n.t('general.archived')}]" : record.name))
+ end
+ row.push(I18n.l(record.created_at, format: :full)) unless excluded_columns.include?(-3)
+ row.push(escape_input(record.created_by.full_name)) unless excluded_columns.include?(-4)
cell_values = {}
custom_cells = record.repository_cells
@@ -38,6 +42,8 @@ module Reports::Docx::RepositoryHelper
end
repository_data[:custom_columns].each do |column_id|
+ next if excluded_columns.include?(column_id)
+
value = cell_values[column_id]
row.push(value)
end
diff --git a/app/views/reports/wizard/_third_step.html.erb b/app/views/reports/wizard/_third_step.html.erb
index 327c1d857..2cbf865db 100644
--- a/app/views/reports/wizard/_third_step.html.erb
+++ b/app/views/reports/wizard/_third_step.html.erb
@@ -55,7 +55,10 @@
- <%= t("projects.reports.wizard.third_step.assigned_items_description") %>
+
+
<%= t("projects.reports.wizard.third_step.assigned_items_description") %>
+
<%= t("projects.reports.wizard.third_step.assigned_items_repository_items_description_html") %>
+
@@ -68,25 +71,50 @@
<% @repositories.each do |repository| %>
-
- />
-
-
- <%= repository.name %>
- <% if repository.archived? %>
-
- <%= t("projects.reports.wizard.third_step.archived") %>
+
+
+ />
+
- <% elsif repository.is_a?(RepositorySnapshot) %>
-
- <%= t("projects.reports.wizard.third_step.deleted") %>
-
- <% end %>
+ <%= repository.name %>
+ <% if repository.archived? %>
+
+ <%= t("projects.reports.wizard.third_step.archived") %>
+
+ <% elsif repository.is_a?(RepositorySnapshot) %>
+
+ <%= t("projects.reports.wizard.third_step.deleted") %>
+
+ <% end %>
+
+ data-combine-tags="true"
+ data-placeholder="<%= t("projects.reports.wizard.third_step.repository_column.placeholder") %>"
+ data-select-multiple-all-selected="<%= t("projects.reports.wizard.third_step.repository_column.all_selected") %>"
+ data-select-multiple-name="<%= t("projects.reports.wizard.third_step.repository_column.selected") %>"
+ multiple
+ >
+ <% Report.default_repository_columns.each do |key, value| %>
+
+ <%= value %>
+
+ <% end %>
+ <% repository.repository_columns.find_each do |repository_column| %>
+
+ <%= repository_column.name %>
+
+ <% end %>
+
+
<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index e3d65629d..371aa7200 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -844,6 +844,7 @@ en:
step_comments: "Step comments"
assigned_items: "Assigned items"
assigned_items_description: "Inventories selected below will only contain the items that you assigned to the tasks directly."
+ assigned_items_repository_items_description_html: "You can customize inventory columns only for the docx report. The stock management column by default reflects item consumption."
include_all_assigned_iitems: "Include all assigned items from the following inventories"
results: "Results"
all_results: "Include all results elements"
@@ -866,6 +867,10 @@ en:
exclude_timestamps: "Exclude timestamps"
archived: "[archived]"
deleted: "[deleted]"
+ repository_column:
+ placeholder: 'Select columns'
+ all_selected: 'All columns selected'
+ selected: 'columns selected'
new:
report_name_placeholder: "Name your report"
From 104825af7980cf3f8f38856db523ca0ad8a4c837 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Wed, 2 Oct 2024 11:05:45 +0200
Subject: [PATCH 29/96] Change how asset sync conflict resolution works with
file versioning [SCI-11043]
---
app/controllers/asset_sync_controller.rb | 27 ++++++++++++------------
config/locales/en.yml | 2 +-
2 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/app/controllers/asset_sync_controller.rb b/app/controllers/asset_sync_controller.rb
index ae8d0e126..968503cd7 100644
--- a/app/controllers/asset_sync_controller.rb
+++ b/app/controllers/asset_sync_controller.rb
@@ -16,7 +16,8 @@ class AssetSyncController < ApplicationController
asset_sync_token = current_user.asset_sync_tokens.find_or_create_by(asset_id: params[:asset_id])
unless asset_sync_token.token_valid?
- asset_sync_token = current_user.asset_sync_tokens.create(asset_id: params[:asset_id])
+ asset_sync_token =
+ current_user.asset_sync_tokens.create(asset_id: params[:asset_id])
end
render json: AssetSyncTokenSerializer.new(asset_sync_token).as_json
@@ -27,18 +28,7 @@ class AssetSyncController < ApplicationController
end
def update
- if @asset_sync_token.conflicts?(request.headers['VersionToken'])
- ActiveRecord::Base.transaction do
- conflict_response = AssetSyncTokenSerializer.new(conflicting_asset_copy_token).as_json
- error_message = { message: I18n.t('assets.conflict_error', filename: @asset.file.filename) }
- log_activity(:create)
- render json: conflict_response.merge(error_message), status: :conflict
- end
-
- return
- end
-
- orig_file_size = @asset.file_size
+ asset_conflicts = @asset_sync_token.conflicts?(request.headers['VersionToken'])
ActiveRecord::Base.transaction do
@asset.update(last_modified_by: current_user)
@@ -49,12 +39,21 @@ class AssetSyncController < ApplicationController
@asset.touch
end
- @asset.team.release_space(orig_file_size)
@asset.post_process_file
log_activity(:edit)
end
+ if asset_conflicts
+ ActiveRecord::Base.transaction do
+ conflict_response = AssetSyncTokenSerializer.new(@asset_sync_token).as_json
+ error_message = { message: I18n.t('assets.conflict_error', filename: @asset.file.filename) }
+ render json: conflict_response.merge(error_message), status: :conflict
+ end
+
+ return
+ end
+
render json: AssetSyncTokenSerializer.new(@asset_sync_token).as_json
end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 397eb5886..570263530 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -4049,7 +4049,7 @@ en:
edit_launching_application_modal:
title: "Launching application"
description: "%{file_name} will now open in %{application}. Saved changes in %{application} will automatically be synced in SciNote."
- conflict_error: "A newer version of the file was already present in the SciNote web app and your file was saved as “%{filename}”. Close this window and re-open file to get the latest changes."
+ conflict_error: "The file got updated in the SciNote web app while you were editing. Your version will be stored as the latest version, and the previous one is kept in version history."
default_error: "An error occurred while saving to SciNote. Please save changes to your open document using “Save As…” to avoid losing any working changes."
default_error_with_filename: "An error occurred while saving “%{filename}” to SciNote. Please save changes to your open document using “Save As…” to avoid losing any working changes."
From 74f3ea2108bba187c03e78299d13fca2aa0927c5 Mon Sep 17 00:00:00 2001
From: Martin Artnik
Date: Wed, 2 Oct 2024 14:22:51 +0200
Subject: [PATCH 30/96] Add file editing & versioning to inventories
[SCI-11043]
---
.../content/attachments/open_locally_menu.vue | 34 +++++++++++++++----
.../shared/file_preview/_content.html.erb | 4 +--
config/locales/en.yml | 2 +-
3 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue
index 8ea7048cc..9d40e11cf 100644
--- a/app/javascript/vue/shared/content/attachments/open_locally_menu.vue
+++ b/app/javascript/vue/shared/content/attachments/open_locally_menu.vue
@@ -1,8 +1,8 @@
-