Skip to content

Commit

Permalink
Merge branch 'features/custom-docx-reports' of github.com:scinote-eln…
Browse files Browse the repository at this point in the history
…/scinote-web into features/custom-docx-reports
  • Loading branch information
aignatov-bio committed Nov 14, 2024
2 parents d3dc404 + 97011d6 commit 1f1ab08
Show file tree
Hide file tree
Showing 53 changed files with 598 additions and 288 deletions.
3 changes: 1 addition & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
16 changes: 11 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ GIT
docile (>= 1.1.0)
rails (>= 4)

GIT
remote: https://github.com/scinote-eln/caracal.git
revision: 54c21353798569476a1eaa73b5fd3e275ac85419
branch: custom-docx-reports
specs:
caracal (1.4.2)
nokogiri (~> 1.6)
rubyzip (>= 2.3)
tilt (>= 1.4)

GIT
remote: https://github.com/scinote-eln/img2zpl
revision: 23d61cfc3e90ac4caa62dd08546fa0d7590a5140
Expand Down Expand Up @@ -210,10 +220,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)
Expand Down Expand Up @@ -790,7 +796,7 @@ DEPENDENCIES
canaid!
capybara
capybara-email
caracal_the_curve (~> 1.4, >= 1.4.6)
caracal!
caxlsx
cssbundling-rails
cucumber-rails
Expand Down
55 changes: 49 additions & 6 deletions app/assets/javascripts/reports/new.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};

Expand All @@ -982,7 +992,7 @@ function reportHandsonTableConverter() {

// Template values
reportData.template_values = {};
$.each($('.report-template-values-container').find('.sci-input-field'), function(i, field) {
$.each($('.report-template-values-container').find('.sci-input-field').not('.report-template-value-dropdown'), (_, field) => {
if (field.value.length === 0) return;

reportData.template_values[field.name] = {
Expand Down Expand Up @@ -1046,12 +1056,24 @@ 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');

reportData.report.settings.exclude_task_metadata = $('.exclude-task-metadata-setting')[0].checked;
reportData.report.settings.exclude_timestamps = $('.exclude-timestamps-setting')[0].checked;

return reportData;
}

Expand Down Expand Up @@ -1256,7 +1278,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);
Expand All @@ -1279,6 +1302,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');
Expand Down Expand Up @@ -1349,10 +1378,24 @@ 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() {
let template = $('#templateSelector').val();
const template = dropdownSelector.getValues('#templateSelector');
let params = {
project_id: dropdownSelector.getValues('#projectSelector'),
template: template
Expand Down Expand Up @@ -1382,7 +1425,7 @@ function reportHandsonTableConverter() {
}

function loadDocxTemplate() {
let template = $('#docxTemplateSelector').val();
const template = dropdownSelector.getValues('#docxTemplateSelector');
let params = {
project_id: dropdownSelector.getValues('#projectSelector'),
template: template
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/sitewide/dropdown_selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ var dropdownSelector = (function() {

// If we setup Select All we draw it and add correspond logic
if (selectElement.data('select-all-button')) {
$(`<div class="dropdown-select-all btn">${selectElement.data('select-all-button')}</div>`)
$(`<div class="dropdown-select-all">${selectElement.data('select-all-button')}</div>`)
.appendTo(dropdownContainer.find('.dropdown-container'))
.click(() => {
// For AJAX dropdown we will use only "Deselect All"
Expand Down
19 changes: 19 additions & 0 deletions app/assets/stylesheets/reports/new.scss
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,25 @@
}
}

// scss-lint:disable ImportantRule
.dropdown-selector-container {
.dropdown-container {
left: auto !important;
margin: auto !important;
position: absolute !important;
}
}
// 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;
Expand Down
4 changes: 4 additions & 0 deletions app/assets/stylesheets/shared/dropdown_selector.scss
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@
top: 0;
width: 100%;
z-index: 5;

&:hover {
background: $color-concrete;
}
}

.dropdown-blank {
Expand Down
5 changes: 2 additions & 3 deletions app/components/reports/repositories_input_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
32 changes: 31 additions & 1 deletion app/controllers/reports_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,6 +45,8 @@ def new
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
Expand All @@ -69,6 +72,7 @@ def new_template_values
else
render json: {
html: render_to_string(partial: 'reports/wizard/no_template_values',
locals: { type: @type, template: @template_name },
formats: :html)
}
end
Expand All @@ -77,6 +81,8 @@ def new_template_values
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
Expand All @@ -102,6 +108,7 @@ def new_docx_template_values
else
render json: {
html: render_to_string(partial: 'reports/wizard/no_template_values',
locals: { type: @type, template: @template_name },
formats: :html)
}
end
Expand Down Expand Up @@ -363,6 +370,9 @@ def load_wizard_vars
.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
Expand Down Expand Up @@ -430,6 +440,26 @@ def generate_pdf_report
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?

Expand Down
3 changes: 2 additions & 1 deletion app/helpers/input_sanitize_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ def custom_auto_link(text, options = {})
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

text = smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository) if text.match?(SmartAnnotations::TagToHtml::ALL_REGEX)

Expand Down
4 changes: 4 additions & 0 deletions app/helpers/reports_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@ def permit_report_settings_structure(settings_definition)
end
end
end

def custom_templates(templates)
templates.any? { |template, _| template != :scinote_template }
end
end
16 changes: 8 additions & 8 deletions app/models/my_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -391,17 +391,17 @@ def repository_json_hot(repository, order)
{ 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'))
Expand All @@ -416,7 +416,7 @@ def repository_docx_json(repository)

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)
Expand Down
14 changes: 13 additions & 1 deletion app/models/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Report < ApplicationRecord

DEFAULT_SETTINGS = {
all_tasks: true,
exclude_task_metadata: false,
exclude_timestamps: false,
task: {
protocol: {
description: true,
Expand All @@ -62,7 +64,8 @@ class Report < ApplicationRecord
result_comments: true,
result_order: 'new',
activities: true,
repositories: []
repositories: [],
excluded_repository_columns: {}
}
}.freeze

Expand Down Expand Up @@ -124,4 +127,13 @@ def self.generate_whole_project_report(project, current_user, current_team)
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
2 changes: 1 addition & 1 deletion app/services/reports/docx.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def initialize(report, docx, options)
@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
Expand Down
Loading

0 comments on commit 1f1ab08

Please sign in to comment.