mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-06 11:57:16 +08:00
Merge branch 'features/custom-docx-reports' of github.com:scinote-eln/scinote-web into features/custom-docx-reports
This commit is contained in:
commit
1f1ab08001
53 changed files with 601 additions and 291 deletions
3
Gemfile
3
Gemfile
|
@ -47,8 +47,7 @@ gem 'aspector' # Aspect-oriented programming for Rails
|
||||||
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces AR
|
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces AR
|
||||||
gem 'bcrypt', '~> 3.1.10'
|
gem 'bcrypt', '~> 3.1.10'
|
||||||
# gem 'caracal'
|
# 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: 'custom-docx-reports' # Build docx report
|
||||||
gem 'caracal_the_curve', '~> 1.4', '>= 1.4.6'
|
|
||||||
gem 'caxlsx' # Build XLSX files
|
gem 'caxlsx' # Build XLSX files
|
||||||
gem 'deface', '~> 1.9'
|
gem 'deface', '~> 1.9'
|
||||||
gem 'down', '~> 5.0'
|
gem 'down', '~> 5.0'
|
||||||
|
|
16
Gemfile.lock
16
Gemfile.lock
|
@ -14,6 +14,16 @@ GIT
|
||||||
docile (>= 1.1.0)
|
docile (>= 1.1.0)
|
||||||
rails (>= 4)
|
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
|
GIT
|
||||||
remote: https://github.com/scinote-eln/img2zpl
|
remote: https://github.com/scinote-eln/img2zpl
|
||||||
revision: 23d61cfc3e90ac4caa62dd08546fa0d7590a5140
|
revision: 23d61cfc3e90ac4caa62dd08546fa0d7590a5140
|
||||||
|
@ -210,10 +220,6 @@ GEM
|
||||||
capybara-email (3.0.2)
|
capybara-email (3.0.2)
|
||||||
capybara (>= 2.4, < 4.0)
|
capybara (>= 2.4, < 4.0)
|
||||||
mail
|
mail
|
||||||
caracal_the_curve (1.4.6)
|
|
||||||
nokogiri (~> 1.6)
|
|
||||||
rubyzip (>= 1.1.0, < 3.0)
|
|
||||||
tilt (>= 1.4)
|
|
||||||
case_transform (0.2)
|
case_transform (0.2)
|
||||||
activesupport
|
activesupport
|
||||||
caxlsx (4.0.0)
|
caxlsx (4.0.0)
|
||||||
|
@ -790,7 +796,7 @@ DEPENDENCIES
|
||||||
canaid!
|
canaid!
|
||||||
capybara
|
capybara
|
||||||
capybara-email
|
capybara-email
|
||||||
caracal_the_curve (~> 1.4, >= 1.4.6)
|
caracal!
|
||||||
caxlsx
|
caxlsx
|
||||||
cssbundling-rails
|
cssbundling-rails
|
||||||
cucumber-rails
|
cucumber-rails
|
||||||
|
|
|
@ -968,6 +968,16 @@ function reportHandsonTableConverter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
(function() {
|
(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() {
|
function getReportData() {
|
||||||
var reportData = {};
|
var reportData = {};
|
||||||
|
|
||||||
|
@ -982,7 +992,7 @@ function reportHandsonTableConverter() {
|
||||||
|
|
||||||
// Template values
|
// Template values
|
||||||
reportData.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;
|
if (field.value.length === 0) return;
|
||||||
|
|
||||||
reportData.template_values[field.name] = {
|
reportData.template_values[field.name] = {
|
||||||
|
@ -1046,12 +1056,24 @@ function reportHandsonTableConverter() {
|
||||||
reportData.report.settings.task[e.value] = e.checked;
|
reportData.report.settings.task[e.value] = e.checked;
|
||||||
});
|
});
|
||||||
reportData.report.settings.task.repositories = [];
|
reportData.report.settings.task.repositories = [];
|
||||||
$.each($('.task-contents-container .repositories-contents .repositories-setting:checked'), function(i, e) {
|
reportData.report.settings.task.excluded_repository_columns = {};
|
||||||
reportData.report.settings.task.repositories.push(parseInt(e.value, 10));
|
|
||||||
|
$.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.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;
|
return reportData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1256,7 +1278,8 @@ function reportHandsonTableConverter() {
|
||||||
function reCheckContinueButton() {
|
function reCheckContinueButton() {
|
||||||
if (dropdownSelector.getValues('#projectSelector').length > 0
|
if (dropdownSelector.getValues('#projectSelector').length > 0
|
||||||
&& dropdownSelector.getValues('#templateSelector').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);
|
$('.continue-button').attr('disabled', false);
|
||||||
} else {
|
} else {
|
||||||
$('.continue-button').attr('disabled', true);
|
$('.continue-button').attr('disabled', true);
|
||||||
|
@ -1279,6 +1302,12 @@ function reportHandsonTableConverter() {
|
||||||
if (dropdownSelector.getValues('#projectSelector').length > 0) {
|
if (dropdownSelector.getValues('#projectSelector').length > 0) {
|
||||||
dropdownSelector.enableSelector('#templateSelector');
|
dropdownSelector.enableSelector('#templateSelector');
|
||||||
dropdownSelector.enableSelector('#docxTemplateSelector');
|
dropdownSelector.enableSelector('#docxTemplateSelector');
|
||||||
|
if ($('#templateSelector').data('defaultTemplate')) {
|
||||||
|
dropdownSelector.selectValues('#templateSelector', $('#templateSelector').data('defaultTemplate'));
|
||||||
|
}
|
||||||
|
if ($('#docxTemplateSelector').data('defaultTemplate')) {
|
||||||
|
dropdownSelector.selectValues('#docxTemplateSelector', $('#docxTemplateSelector').data('defaultTemplate'));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dropdownSelector.selectValues('#templateSelector', '');
|
dropdownSelector.selectValues('#templateSelector', '');
|
||||||
dropdownSelector.disableSelector('#templateSelector');
|
dropdownSelector.disableSelector('#templateSelector');
|
||||||
|
@ -1349,10 +1378,24 @@ function reportHandsonTableConverter() {
|
||||||
if (dropdownSelector.getValues('#docxTemplateSelector').length > 0) {
|
if (dropdownSelector.getValues('#docxTemplateSelector').length > 0) {
|
||||||
loadDocxTemplate();
|
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() {
|
function loadTemplate() {
|
||||||
let template = $('#templateSelector').val();
|
const template = dropdownSelector.getValues('#templateSelector');
|
||||||
let params = {
|
let params = {
|
||||||
project_id: dropdownSelector.getValues('#projectSelector'),
|
project_id: dropdownSelector.getValues('#projectSelector'),
|
||||||
template: template
|
template: template
|
||||||
|
@ -1382,7 +1425,7 @@ function reportHandsonTableConverter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadDocxTemplate() {
|
function loadDocxTemplate() {
|
||||||
let template = $('#docxTemplateSelector').val();
|
const template = dropdownSelector.getValues('#docxTemplateSelector');
|
||||||
let params = {
|
let params = {
|
||||||
project_id: dropdownSelector.getValues('#projectSelector'),
|
project_id: dropdownSelector.getValues('#projectSelector'),
|
||||||
template: template
|
template: template
|
||||||
|
|
|
@ -353,7 +353,7 @@ var dropdownSelector = (function() {
|
||||||
|
|
||||||
// If we setup Select All we draw it and add correspond logic
|
// If we setup Select All we draw it and add correspond logic
|
||||||
if (selectElement.data('select-all-button')) {
|
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'))
|
.appendTo(dropdownContainer.find('.dropdown-container'))
|
||||||
.click(() => {
|
.click(() => {
|
||||||
// For AJAX dropdown we will use only "Deselect All"
|
// For AJAX dropdown we will use only "Deselect All"
|
||||||
|
|
|
@ -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 {
|
.project-selector-container {
|
||||||
background: $color-white;
|
background: $color-white;
|
||||||
box-shadow: $modal-shadow;
|
box-shadow: $modal-shadow;
|
||||||
|
|
|
@ -175,6 +175,10 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $color-concrete;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-blank {
|
.dropdown-blank {
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
module Reports
|
module Reports
|
||||||
class RepositoriesInputComponent < TemplateValueComponent
|
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)
|
super(report: report, name: name, label: label, placeholder: placeholder, editing: editing)
|
||||||
|
live_repositories = Repository.viewable_by_user(user, report.team).sort_by { |r| r.name.downcase }
|
||||||
live_repositories = Repository.accessible_by_teams(report.team).sort_by { |r| r.name.downcase }
|
|
||||||
snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
|
snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
|
||||||
.where(team: report.team)
|
.where(team: report.team)
|
||||||
.where.not(original_repository: live_repositories)
|
.where.not(original_repository: live_repositories)
|
||||||
|
|
|
@ -18,7 +18,8 @@ class ReportsController < ApplicationController
|
||||||
before_action :check_create_permissions, only: %i(new create)
|
before_action :check_create_permissions, only: %i(new create)
|
||||||
before_action :check_manage_permissions, only: %i(edit update generate_pdf generate_docx)
|
before_action :check_manage_permissions, only: %i(edit update generate_pdf generate_docx)
|
||||||
before_action :switch_team_with_param, only: :index
|
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
|
# Index showing all reports of a single project
|
||||||
def index
|
def index
|
||||||
|
@ -44,6 +45,8 @@ class ReportsController < ApplicationController
|
||||||
def new_template_values
|
def new_template_values
|
||||||
if Extends::REPORT_TEMPLATES.key?(params[:template]&.to_sym)
|
if Extends::REPORT_TEMPLATES.key?(params[:template]&.to_sym)
|
||||||
template = params[:template]
|
template = params[:template]
|
||||||
|
@type = :pdf
|
||||||
|
@template_name = Extends::REPORT_TEMPLATES[params[:template].to_sym]
|
||||||
else
|
else
|
||||||
return render_404
|
return render_404
|
||||||
end
|
end
|
||||||
|
@ -69,6 +72,7 @@ class ReportsController < ApplicationController
|
||||||
else
|
else
|
||||||
render json: {
|
render json: {
|
||||||
html: render_to_string(partial: 'reports/wizard/no_template_values',
|
html: render_to_string(partial: 'reports/wizard/no_template_values',
|
||||||
|
locals: { type: @type, template: @template_name },
|
||||||
formats: :html)
|
formats: :html)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -77,6 +81,8 @@ class ReportsController < ApplicationController
|
||||||
def new_docx_template_values
|
def new_docx_template_values
|
||||||
if Extends::DOCX_REPORT_TEMPLATES.key?(params[:template]&.to_sym)
|
if Extends::DOCX_REPORT_TEMPLATES.key?(params[:template]&.to_sym)
|
||||||
template = params[:template]
|
template = params[:template]
|
||||||
|
@type = :docx
|
||||||
|
@template_name = Extends::DOCX_REPORT_TEMPLATES[params[:template].to_sym]
|
||||||
else
|
else
|
||||||
return render_404
|
return render_404
|
||||||
end
|
end
|
||||||
|
@ -102,6 +108,7 @@ class ReportsController < ApplicationController
|
||||||
else
|
else
|
||||||
render json: {
|
render json: {
|
||||||
html: render_to_string(partial: 'reports/wizard/no_template_values',
|
html: render_to_string(partial: 'reports/wizard/no_template_values',
|
||||||
|
locals: { type: @type, template: @template_name },
|
||||||
formats: :html)
|
formats: :html)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -363,6 +370,9 @@ class ReportsController < ApplicationController
|
||||||
.merge(MyModule.active)
|
.merge(MyModule.active)
|
||||||
.group(:id)
|
.group(:id)
|
||||||
.select(:id, :name)
|
.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
|
end
|
||||||
|
|
||||||
def check_project_read_permissions
|
def check_project_read_permissions
|
||||||
|
@ -430,6 +440,26 @@ class ReportsController < ApplicationController
|
||||||
Rails.logger.error e.message
|
Rails.logger.error e.message
|
||||||
end
|
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!
|
def ensure_report_template!
|
||||||
return if @report.settings['template'].present?
|
return if @report.settings['template'].present?
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,12 @@ module InputSanitizeHelper
|
||||||
preview_repository = options.fetch(:preview_repository, false)
|
preview_repository = options.fetch(:preview_repository, false)
|
||||||
format_opt = wrapper_tag.merge(sanitize: false)
|
format_opt = wrapper_tag.merge(sanitize: false)
|
||||||
base64_encoded_imgs = options.fetch(:base64_encoded_imgs, 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
|
# allow base64 images when sanitizing if base64_encoded_imgs is true
|
||||||
sanitizer_config = Constants::INPUT_SANITIZE_CONFIG.deep_dup
|
sanitizer_config = Constants::INPUT_SANITIZE_CONFIG.deep_dup
|
||||||
|
|
||||||
text = sanitize_input(text, tags, sanitizer_config: sanitizer_config)
|
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)
|
text = smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository) if text.match?(SmartAnnotations::TagToHtml::ALL_REGEX)
|
||||||
|
|
||||||
|
|
|
@ -119,4 +119,8 @@ module ReportsHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def custom_templates(templates)
|
||||||
|
templates.any? { |template, _| template != :scinote_template }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -391,17 +391,17 @@ class MyModule < ApplicationRecord
|
||||||
{ data: data, headers: headers }
|
{ data: data, headers: headers }
|
||||||
end
|
end
|
||||||
|
|
||||||
def repository_docx_json(repository)
|
def repository_docx_json(repository, excluded_columns)
|
||||||
headers = [
|
headers = Report.default_repository_columns.filter_map do |key, value|
|
||||||
I18n.t('repositories.table.id'),
|
value unless excluded_columns.include?(key.to_s.to_i)
|
||||||
I18n.t('repositories.table.row_name'),
|
end
|
||||||
I18n.t('repositories.table.added_on'),
|
|
||||||
I18n.t('repositories.table.added_by')
|
|
||||||
]
|
|
||||||
custom_columns = []
|
custom_columns = []
|
||||||
return false unless repository
|
return false unless repository
|
||||||
|
|
||||||
repository.repository_columns.order(:id).each do |column|
|
repository.repository_columns.order(:id).each do |column|
|
||||||
|
next if excluded_columns.include?(column.id)
|
||||||
|
|
||||||
if column.data_type == 'RepositoryStockValue'
|
if column.data_type == 'RepositoryStockValue'
|
||||||
if repository.has_stock_consumption?
|
if repository.has_stock_consumption?
|
||||||
headers.push(I18n.t('repositories.table.row_consumption'))
|
headers.push(I18n.t('repositories.table.row_consumption'))
|
||||||
|
@ -416,7 +416,7 @@ class MyModule < ApplicationRecord
|
||||||
|
|
||||||
records = repository.assigned_rows(self)
|
records = repository.assigned_rows(self)
|
||||||
.select(:id, :name, :created_at, :created_by_id, :repository_id, :parent_id, :archived)
|
.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
|
end
|
||||||
|
|
||||||
def deep_clone(current_user)
|
def deep_clone(current_user)
|
||||||
|
|
|
@ -43,6 +43,8 @@ class Report < ApplicationRecord
|
||||||
|
|
||||||
DEFAULT_SETTINGS = {
|
DEFAULT_SETTINGS = {
|
||||||
all_tasks: true,
|
all_tasks: true,
|
||||||
|
exclude_task_metadata: false,
|
||||||
|
exclude_timestamps: false,
|
||||||
task: {
|
task: {
|
||||||
protocol: {
|
protocol: {
|
||||||
description: true,
|
description: true,
|
||||||
|
@ -62,7 +64,8 @@ class Report < ApplicationRecord
|
||||||
result_comments: true,
|
result_comments: true,
|
||||||
result_order: 'new',
|
result_order: 'new',
|
||||||
activities: true,
|
activities: true,
|
||||||
repositories: []
|
repositories: [],
|
||||||
|
excluded_repository_columns: {}
|
||||||
}
|
}
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
@ -124,4 +127,13 @@ class Report < ApplicationRecord
|
||||||
ReportActions::ReportContent.new(report, content, {}, current_user).save_with_content
|
ReportActions::ReportContent.new(report, content, {}, current_user).save_with_content
|
||||||
report
|
report
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Reports::Docx
|
||||||
@link_style = {}
|
@link_style = {}
|
||||||
@color = {}
|
@color = {}
|
||||||
@scinote_url = options[:scinote_url][0..-2]
|
@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
|
extend "#{@template.camelize}Docx".constantize
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Reports::Docx::DrawExperiment
|
||||||
def draw_experiment(subject)
|
def draw_experiment(subject)
|
||||||
color = @color
|
color = @color
|
||||||
link_style = @link_style
|
link_style = @link_style
|
||||||
|
settings = @settings
|
||||||
scinote_url = @scinote_url
|
scinote_url = @scinote_url
|
||||||
experiment = subject.experiment
|
experiment = subject.experiment
|
||||||
return unless can_read_experiment?(@user, experiment)
|
return unless can_read_experiment?(@user, experiment)
|
||||||
|
@ -14,12 +15,15 @@ module Reports::Docx::DrawExperiment
|
||||||
link_style
|
link_style
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if !settings['exclude_timestamps'] || experiment.archived?
|
||||||
@docx.p do
|
@docx.p do
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text I18n.t('projects.reports.elements.experiment.user_time',
|
text I18n.t('projects.reports.elements.experiment.user_time',
|
||||||
code: experiment.code, timestamp: I18n.l(experiment.created_at, format: :full)), color: color[:gray]
|
code: experiment.code,
|
||||||
if experiment.archived?
|
timestamp: I18n.l(experiment.created_at, format: :full)), color: color[:gray]
|
||||||
text ' | '
|
text ' | ' if experiment.archived?
|
||||||
text I18n.t('search.index.archived'), color: color[:gray]
|
end
|
||||||
|
text I18n.t('search.index.archived'), color: color[:gray] if experiment.archived?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
html = custom_auto_link(experiment.description, team: @report_team)
|
html = custom_auto_link(experiment.description, team: @report_team)
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Reports::Docx::DrawMyModule
|
||||||
def draw_my_module(subject, without_results: false, without_repositories: false)
|
def draw_my_module(subject, without_results: false, without_repositories: false)
|
||||||
color = @color
|
color = @color
|
||||||
link_style = @link_style
|
link_style = @link_style
|
||||||
|
settings = @settings
|
||||||
scinote_url = @scinote_url
|
scinote_url = @scinote_url
|
||||||
my_module = subject.my_module
|
my_module = subject.my_module
|
||||||
tags = my_module.tags.order(:id)
|
tags = my_module.tags.order(:id)
|
||||||
|
@ -15,15 +16,19 @@ module Reports::Docx::DrawMyModule
|
||||||
link_style
|
link_style
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if my_module.archived? || !settings['exclude_timestamps']
|
||||||
@docx.p do
|
@docx.p do
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text I18n.t('projects.reports.elements.module.user_time', code: my_module.code,
|
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]
|
timestamp: I18n.l(my_module.created_at, format: :full)), color: color[:gray]
|
||||||
if my_module.archived?
|
text ' | ' if my_module.archived?
|
||||||
text ' | '
|
end
|
||||||
text I18n.t('search.index.archived'), color: color[:gray]
|
|
||||||
|
text I18n.t('search.index.archived'), color: color[:gray] if my_module.archived?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless settings['exclude_task_metadata']
|
||||||
if my_module.started_on.present?
|
if my_module.started_on.present?
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text I18n.t('projects.reports.elements.module.started_on',
|
text I18n.t('projects.reports.elements.module.started_on',
|
||||||
|
@ -57,6 +62,7 @@ module Reports::Docx::DrawMyModule
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if my_module.description.present?
|
if my_module.description.present?
|
||||||
html = custom_auto_link(my_module.description, team: @report_team)
|
html = custom_auto_link(my_module.description, team: @report_team)
|
||||||
|
@ -69,10 +75,13 @@ module Reports::Docx::DrawMyModule
|
||||||
filter_steps_for_report(my_module.protocol.steps, @settings).order(:position).each do |step|
|
filter_steps_for_report(my_module.protocol.steps, @settings).order(:position).each do |step|
|
||||||
draw_step(step)
|
draw_step(step)
|
||||||
end
|
end
|
||||||
|
|
||||||
draw_results(my_module) unless without_results
|
|
||||||
|
|
||||||
@docx.p
|
@docx.p
|
||||||
|
|
||||||
|
unless without_results
|
||||||
|
draw_results(my_module)
|
||||||
|
@docx.p
|
||||||
|
end
|
||||||
|
|
||||||
subject.children.active.each do |child|
|
subject.children.active.each do |child|
|
||||||
next if without_repositories && child.type_of == 'my_module_repository'
|
next if without_repositories && child.type_of == 'my_module_repository'
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,14 @@ module Reports::Docx::DrawMyModuleProtocol
|
||||||
end
|
end
|
||||||
|
|
||||||
if @settings.dig('task', 'protocol', 'description') && protocol.description.present?
|
if @settings.dig('task', 'protocol', 'description') && protocol.description.present?
|
||||||
|
unless @settings['exclude_timestamps']
|
||||||
@docx.p I18n.t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code,
|
@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]
|
timestamp: I18n.l(protocol.created_at, format: :full)), color: @color[:gray]
|
||||||
|
end
|
||||||
html = custom_auto_link(protocol.description, team: @report_team)
|
html = custom_auto_link(protocol.description, team: @report_team)
|
||||||
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
||||||
link_style: @link_style }).html_to_word_converter(html)
|
link_style: @link_style }).html_to_word_converter(html)
|
||||||
@docx.p
|
@docx.p
|
||||||
@docx.p
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,11 +5,12 @@ module Reports::Docx::DrawMyModuleRepository
|
||||||
my_module = subject.my_module
|
my_module = subject.my_module
|
||||||
repository = subject.repository
|
repository = subject.repository
|
||||||
repository = assigned_repository_or_snapshot(my_module, 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) &&
|
return unless repository && can_read_experiment?(@user, my_module.experiment) &&
|
||||||
(repository.is_a?(RepositorySnapshot) || can_read_repository?(@user, repository))
|
(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)
|
return false unless repository_data[:rows].any? && can_read_repository?(@user, repository)
|
||||||
|
|
||||||
|
@ -19,7 +20,12 @@ module Reports::Docx::DrawMyModuleRepository
|
||||||
@docx.p I18n.t('projects.reports.elements.module_repository.name',
|
@docx.p I18n.t('projects.reports.elements.module_repository.name',
|
||||||
repository: repository.name,
|
repository: repository.name,
|
||||||
my_module: my_module.name), bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
|
my_module: my_module.name), bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
|
||||||
|
|
||||||
|
if table.present?
|
||||||
@docx.table table, border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
|
@docx.table table, border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
|
||||||
|
else
|
||||||
|
@docx.p I18n.t('projects.reports.elements.module_repository.no_columns'), italic: true
|
||||||
|
end
|
||||||
|
|
||||||
@docx.p
|
@docx.p
|
||||||
@docx.p
|
@docx.p
|
||||||
|
|
|
@ -15,6 +15,7 @@ module Reports::Docx::DrawProjectHeader
|
||||||
link_style
|
link_style
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless @settings['exclude_timestamps']
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text I18n.t('projects.reports.elements.project_header.user_time', code: project.code,
|
text I18n.t('projects.reports.elements.project_header.user_time', code: project.code,
|
||||||
timestamp: I18n.l(project.created_at, format: :full)), color: color[:gray]
|
timestamp: I18n.l(project.created_at, format: :full)), color: color[:gray]
|
||||||
|
@ -22,3 +23,4 @@ module Reports::Docx::DrawProjectHeader
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -25,11 +25,9 @@ module Reports::Docx::DrawResultAsset
|
||||||
end
|
end
|
||||||
text " #{I18n.t('search.index.archived')} ", bold: true if result.archived?
|
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.file_name', file: asset.file_name)
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text ' ' + I18n.t('projects.reports.elements.result_asset.user_time',
|
text ' ' + I18n.t('projects.reports.elements.result_asset.user_time',
|
||||||
user: result.user.full_name, timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
user: result.user.full_name, timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
||||||
|
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,10 @@ module Reports::Docx::DrawResultComments
|
||||||
@docx.p
|
@docx.p
|
||||||
@docx.p I18n.t('projects.reports.elements.result_comments.name', result: result.name),
|
@docx.p I18n.t('projects.reports.elements.result_comments.name', result: result.name),
|
||||||
bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
|
bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
|
||||||
comments.each do |comment|
|
comments.find_each.with_index do |comment, index|
|
||||||
comment_ts = comment.created_at
|
comment_ts = comment.created_at
|
||||||
|
|
||||||
|
@docx.p unless index.zero?
|
||||||
@docx.p I18n.t('projects.reports.elements.result_comments.comment_prefix',
|
@docx.p I18n.t('projects.reports.elements.result_comments.comment_prefix',
|
||||||
user: comment.user.full_name,
|
user: comment.user.full_name,
|
||||||
date: I18n.l(comment_ts, format: :full_date),
|
date: I18n.l(comment_ts, format: :full_date),
|
||||||
|
@ -17,7 +19,6 @@ module Reports::Docx::DrawResultComments
|
||||||
html = custom_auto_link(comment.message, team: @report_team)
|
html = custom_auto_link(comment.message, team: @report_team)
|
||||||
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
||||||
link_style: @link_style }).html_to_word_converter(html)
|
link_style: @link_style }).html_to_word_converter(html)
|
||||||
@docx.p
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module Reports::Docx::DrawResultTable
|
||||||
result = element.result
|
result = element.result
|
||||||
table = element.orderable.table
|
table = element.orderable.table
|
||||||
timestamp = table.created_at
|
timestamp = table.created_at
|
||||||
|
settings = @settings
|
||||||
color = @color
|
color = @color
|
||||||
obj = self
|
obj = self
|
||||||
table_data = JSON.parse(table.contents_utf_8)['data']
|
table_data = JSON.parse(table.contents_utf_8)['data']
|
||||||
|
@ -39,9 +40,11 @@ module Reports::Docx::DrawResultTable
|
||||||
end
|
end
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text I18n.t 'projects.reports.elements.result_table.table_name', name: table.name
|
text I18n.t 'projects.reports.elements.result_table.table_name', name: table.name
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text ' '
|
text ' '
|
||||||
text I18n.t('projects.reports.elements.result_table.user_time',
|
text I18n.t('projects.reports.elements.result_table.user_time',
|
||||||
timestamp: I18n.l(timestamp, format: :full), user: result.user.full_name), color: color[:gray]
|
timestamp: I18n.l(timestamp, format: :full), user: result.user.full_name), color: color[:gray]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -4,13 +4,19 @@ module Reports::Docx::DrawResultText
|
||||||
def draw_result_text(element)
|
def draw_result_text(element)
|
||||||
result_text = element.orderable
|
result_text = element.orderable
|
||||||
timestamp = element.created_at
|
timestamp = element.created_at
|
||||||
|
settings = @settings
|
||||||
color = @color
|
color = @color
|
||||||
|
if result_text.name.present? || !settings['exclude_timestamps']
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text result_text.name.presence || '', italic: true
|
text result_text.name.to_s, italic: true
|
||||||
text ' '
|
text ' ' if result_text.name.present?
|
||||||
|
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text I18n.t('projects.reports.elements.result_text.user_time',
|
text I18n.t('projects.reports.elements.result_text.user_time',
|
||||||
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
html = custom_auto_link(result_text.text, team: @report_team)
|
html = custom_auto_link(result_text.text, team: @report_team)
|
||||||
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
||||||
link_style: @link_style }).html_to_word_converter(html)
|
link_style: @link_style }).html_to_word_converter(html)
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Reports::Docx::DrawResults
|
module Reports::Docx::DrawResults
|
||||||
def draw_results(my_module)
|
def draw_results(my_module, with_my_module_name: false)
|
||||||
color = @color
|
color = @color
|
||||||
|
settings = @settings
|
||||||
|
scinote_url = @scinote_url
|
||||||
|
link_style = @link_style
|
||||||
return unless can_read_my_module?(@user, my_module)
|
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) })
|
if my_module.results.any? && (%w(file_results table_results text_results).any? { |k| @settings.dig('task', k) })
|
||||||
|
if with_my_module_name
|
||||||
|
@docx.h3 do
|
||||||
|
link my_module.name,
|
||||||
|
scinote_url + Rails.application.routes.url_helpers.protocols_my_module_path(my_module),
|
||||||
|
link_style
|
||||||
|
end
|
||||||
|
end
|
||||||
@docx.h4 I18n.t('Results')
|
@docx.h4 I18n.t('Results')
|
||||||
order_results_for_report(my_module.results, @settings.dig('task', 'result_order')).each do |result|
|
order_results_for_report(my_module.results, @settings.dig('task', 'result_order')).each do |result|
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text result.name.presence || I18n.t('projects.reports.unnamed'), italic: true
|
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('search.index.archived')} ", bold: true if result.archived?
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text I18n.t('projects.reports.elements.result.user_time',
|
text I18n.t('projects.reports.elements.result.user_time',
|
||||||
timestamp: I18n.l(result.created_at, format: :full),
|
timestamp: I18n.l(result.created_at, format: :full),
|
||||||
user: result.user.full_name), color: color[:gray]
|
user: result.user.full_name), color: color[:gray]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
draw_result_asset(result, @settings) if @settings.dig('task', 'file_results')
|
draw_result_asset(result, @settings) if @settings.dig('task', 'file_results')
|
||||||
result.result_orderable_elements.each do |element|
|
result.result_orderable_elements.each do |element|
|
||||||
if @settings.dig('task', 'table_results') && element.orderable_type == 'ResultTable'
|
if @settings.dig('task', 'table_results') && element.orderable_type == 'ResultTable'
|
||||||
|
|
|
@ -6,23 +6,31 @@ module Reports::Docx::DrawStep
|
||||||
step_type_str = step.completed ? 'completed' : 'uncompleted'
|
step_type_str = step.completed ? 'completed' : 'uncompleted'
|
||||||
user = (step.completed? && step.last_modified_by) || step.user
|
user = (step.completed? && step.last_modified_by) || step.user
|
||||||
timestamp = step.completed ? step.completed_on : step.created_at
|
timestamp = step.completed ? step.completed_on : step.created_at
|
||||||
|
settings = @settings
|
||||||
@docx.p
|
@docx.p
|
||||||
@docx.h4(
|
@docx.h4(
|
||||||
"#{I18n.t('projects.reports.elements.step.step_pos', pos: step.position_plus_one)} #{step.name}"
|
"#{I18n.t('projects.reports.elements.step.step_pos', pos: step.position_plus_one)} #{step.name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
unless settings['exclude_task_metadata'] || settings['exclude_timestamps']
|
||||||
@docx.p do
|
@docx.p do
|
||||||
|
unless settings['exclude_task_metadata']
|
||||||
if step.completed
|
if step.completed
|
||||||
text I18n.t('protocols.steps.completed'), color: color[:green], bold: true
|
text I18n.t('protocols.steps.completed'), color: color[:green], bold: true
|
||||||
else
|
else
|
||||||
text I18n.t('protocols.steps.uncompleted'), color: color[:gray], bold: true
|
text I18n.t('protocols.steps.uncompleted'), color: color[:gray], bold: true
|
||||||
end
|
end
|
||||||
text ' | '
|
end
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
|
text ' | ' unless settings['exclude_task_metadata']
|
||||||
text I18n.t(
|
text I18n.t(
|
||||||
"projects.reports.elements.step.#{step_type_str}.user_time",
|
"projects.reports.elements.step.#{step_type_str}.user_time",
|
||||||
user: user.full_name,
|
user: user.full_name,
|
||||||
timestamp: I18n.l(timestamp, format: :full)
|
timestamp: I18n.l(timestamp, format: :full)
|
||||||
), color: color[:gray]
|
), color: color[:gray]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
step.step_orderable_elements.order(:position).each do |element|
|
step.step_orderable_elements.order(:position).each do |element|
|
||||||
case element.orderable_type
|
case element.orderable_type
|
||||||
|
@ -41,9 +49,6 @@ module Reports::Docx::DrawStep
|
||||||
end
|
end
|
||||||
|
|
||||||
draw_step_comments(step) if @settings.dig('task', 'protocol', 'step_comments')
|
draw_step_comments(step) if @settings.dig('task', 'protocol', 'step_comments')
|
||||||
|
|
||||||
@docx.p
|
|
||||||
@docx.p
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_step_table(table)
|
def handle_step_table(table)
|
||||||
|
|
|
@ -5,6 +5,7 @@ module Reports::Docx::DrawStepAsset
|
||||||
timestamp = asset.created_at
|
timestamp = asset.created_at
|
||||||
asset_url = Rails.application.routes.url_helpers.asset_download_url(asset)
|
asset_url = Rails.application.routes.url_helpers.asset_download_url(asset)
|
||||||
color = @color
|
color = @color
|
||||||
|
settings = @settings
|
||||||
@docx.p
|
@docx.p
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -22,9 +23,11 @@ module Reports::Docx::DrawStepAsset
|
||||||
link I18n.t('projects.reports.elements.download'), asset_url do
|
link I18n.t('projects.reports.elements.download'), asset_url do
|
||||||
italic true
|
italic true
|
||||||
end
|
end
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text ' '
|
text ' '
|
||||||
text I18n.t('projects.reports.elements.step_asset.user_time',
|
text I18n.t('projects.reports.elements.step_asset.user_time',
|
||||||
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Reports::Docx::DrawStepChecklist
|
||||||
def draw_step_checklist(checklist)
|
def draw_step_checklist(checklist)
|
||||||
team = @report_team
|
team = @report_team
|
||||||
user = @user
|
user = @user
|
||||||
|
settings = @settings
|
||||||
|
|
||||||
items = checklist.checklist_items
|
items = checklist.checklist_items
|
||||||
timestamp = checklist.created_at
|
timestamp = checklist.created_at
|
||||||
|
@ -15,10 +16,12 @@ module Reports::Docx::DrawStepChecklist
|
||||||
team,
|
team,
|
||||||
I18n.t('projects.reports.elements.step_checklist.checklist_name', name: checklist.name)
|
I18n.t('projects.reports.elements.step_checklist.checklist_name', name: checklist.name)
|
||||||
).text, italic: true
|
).text, italic: true
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text ' '
|
text ' '
|
||||||
text I18n.t('projects.reports.elements.step_checklist.user_time',
|
text I18n.t('projects.reports.elements.step_checklist.user_time',
|
||||||
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
if items.any?
|
if items.any?
|
||||||
@docx.ul do
|
@docx.ul do
|
||||||
items.each do |item|
|
items.each do |item|
|
||||||
|
|
|
@ -8,8 +8,10 @@ module Reports::Docx::DrawStepComments
|
||||||
@docx.p
|
@docx.p
|
||||||
@docx.p I18n.t('projects.reports.elements.step_comments.name', step: step.name),
|
@docx.p I18n.t('projects.reports.elements.step_comments.name', step: step.name),
|
||||||
bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
|
bold: true, size: Constants::REPORT_DOCX_STEP_ELEMENTS_TITLE_SIZE
|
||||||
comments.each do |comment|
|
comments.find_each.with_index do |comment, index|
|
||||||
comment_ts = comment.created_at
|
comment_ts = comment.created_at
|
||||||
|
|
||||||
|
@docx.p unless index.zero?
|
||||||
@docx.p I18n.t('projects.reports.elements.step_comments.comment_prefix',
|
@docx.p I18n.t('projects.reports.elements.step_comments.comment_prefix',
|
||||||
user: comment.user.full_name,
|
user: comment.user.full_name,
|
||||||
date: I18n.l(comment_ts, format: :full_date),
|
date: I18n.l(comment_ts, format: :full_date),
|
||||||
|
@ -17,7 +19,6 @@ module Reports::Docx::DrawStepComments
|
||||||
html = custom_auto_link(comment.message, team: @report_team)
|
html = custom_auto_link(comment.message, team: @report_team)
|
||||||
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
||||||
link_style: @link_style }).html_to_word_converter(html)
|
link_style: @link_style }).html_to_word_converter(html)
|
||||||
@docx.p
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Reports::Docx::DrawStepTable
|
||||||
def draw_step_table(table, table_type)
|
def draw_step_table(table, table_type)
|
||||||
color = @color
|
color = @color
|
||||||
timestamp = table.created_at
|
timestamp = table.created_at
|
||||||
|
settings = @settings
|
||||||
obj = self
|
obj = self
|
||||||
table_data = JSON.parse(table.contents_utf_8)['data']
|
table_data = JSON.parse(table.contents_utf_8)['data']
|
||||||
table_data = obj.add_headers_to_table(table_data, table_type == 'step_well_plates_table')
|
table_data = obj.add_headers_to_table(table_data, table_type == 'step_well_plates_table')
|
||||||
|
@ -38,9 +39,11 @@ module Reports::Docx::DrawStepTable
|
||||||
end
|
end
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text I18n.t("projects.reports.elements.#{table_type}.table_name", name: table.name), italic: true
|
text I18n.t("projects.reports.elements.#{table_type}.table_name", name: table.name), italic: true
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text ' '
|
text ' '
|
||||||
text I18n.t("projects.reports.elements.#{table_type}.user_time",
|
text I18n.t("projects.reports.elements.#{table_type}.user_time",
|
||||||
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -5,12 +5,19 @@ module Reports::Docx::DrawStepText
|
||||||
step_text = element.orderable
|
step_text = element.orderable
|
||||||
timestamp = element.created_at
|
timestamp = element.created_at
|
||||||
color = @color
|
color = @color
|
||||||
|
settings = @settings
|
||||||
|
|
||||||
|
if step_text.name.present? || !settings['exclude_timestamps']
|
||||||
@docx.p do
|
@docx.p do
|
||||||
text step_text.name.presence || '', italic: true
|
text step_text.name.to_s, italic: true
|
||||||
text ' '
|
text ' ' if step_text.name.present?
|
||||||
|
|
||||||
|
unless settings['exclude_timestamps']
|
||||||
text I18n.t('projects.reports.elements.result_text.user_time',
|
text I18n.t('projects.reports.elements.result_text.user_time',
|
||||||
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
timestamp: I18n.l(timestamp, format: :full)), color: color[:gray]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
if step_text.text.present?
|
if step_text.text.present?
|
||||||
html = custom_auto_link(step_text.text, team: @report_team)
|
html = custom_auto_link(step_text.text, team: @report_team)
|
||||||
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
Reports::HtmlToWordConverter.new(@docx, { scinote_url: @scinote_url,
|
||||||
|
|
|
@ -4,15 +4,20 @@ module Reports::Docx::RepositoryHelper
|
||||||
include InputSanitizeHelper
|
include InputSanitizeHelper
|
||||||
include ActionView::Helpers::NumberHelper
|
include ActionView::Helpers::NumberHelper
|
||||||
|
|
||||||
|
|
||||||
def prepare_row_columns_for_docx(repository_data, my_module = nil, repository = nil)
|
def prepare_row_columns_for_docx(repository_data, my_module = nil, repository = nil)
|
||||||
|
return if repository_data[:headers].blank?
|
||||||
|
|
||||||
result = [repository_data[:headers]]
|
result = [repository_data[:headers]]
|
||||||
|
excluded_columns = repository_data[:excluded_columns]
|
||||||
|
|
||||||
repository_data[:rows].each do |record|
|
repository_data[:rows].each do |record|
|
||||||
row = []
|
row = []
|
||||||
row.push(record.code)
|
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))
|
row.push(escape_input(record.archived ? "#{record.name} [#{I18n.t('general.archived')}]" : record.name))
|
||||||
row.push(I18n.l(record.created_at, format: :full))
|
end
|
||||||
row.push(escape_input(record.created_by.full_name))
|
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 = {}
|
cell_values = {}
|
||||||
custom_cells = record.repository_cells
|
custom_cells = record.repository_cells
|
||||||
|
@ -39,6 +44,8 @@ module Reports::Docx::RepositoryHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
repository_data[:custom_columns].each do |column_id|
|
repository_data[:custom_columns].each do |column_id|
|
||||||
|
next if excluded_columns.include?(column_id)
|
||||||
|
|
||||||
value = cell_values[column_id]
|
value = cell_values[column_id]
|
||||||
row.push(value)
|
row.push(value)
|
||||||
end
|
end
|
||||||
|
|
|
@ -130,6 +130,13 @@ module Reports
|
||||||
row[:data].each do |cell|
|
row[:data].each do |cell|
|
||||||
docx_cell = Caracal::Core::Models::TableCellModel.new do |c|
|
docx_cell = Caracal::Core::Models::TableCellModel.new do |c|
|
||||||
cell.each do |content|
|
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'
|
if content[:type] == 'p'
|
||||||
Reports::DocxRenderer.render_p_element(c, content, options.merge({ skip_br: true }))
|
Reports::DocxRenderer.render_p_element(c, content, options.merge({ skip_br: true }))
|
||||||
elsif content[:type] == 'table'
|
elsif content[:type] == 'table'
|
||||||
|
|
|
@ -208,7 +208,7 @@ module Reports
|
||||||
|
|
||||||
if style
|
if style
|
||||||
style_keys.each do |key|
|
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
|
next unless style_el
|
||||||
|
|
||||||
value = style_el.split(':')[1].strip if style_el
|
value = style_el.split(':')[1].strip if style_el
|
||||||
|
@ -259,6 +259,29 @@ module Reports
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def table_cell_styling(elem)
|
||||||
|
style = elem.attributes['style']
|
||||||
|
result = {}
|
||||||
|
style_keys = %w(background-color vertical-align background)
|
||||||
|
|
||||||
|
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', 'background'
|
||||||
|
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)
|
def tiny_mce_table_element(table_element)
|
||||||
# array of elements
|
# array of elements
|
||||||
rows = table_element.css('tbody').first.children.map do |row|
|
rows = table_element.css('tbody').first.children.map do |row|
|
||||||
|
@ -267,11 +290,13 @@ module Reports
|
||||||
cells = row.children.map do |cell|
|
cells = row.children.map do |cell|
|
||||||
next unless cell.name == 'td'
|
next unless cell.name == 'td'
|
||||||
|
|
||||||
|
style = table_cell_styling(cell)
|
||||||
# Parse cell content
|
# Parse cell content
|
||||||
formated_cell = recursive_children(cell.children, [], true)
|
formated_cell = recursive_children(cell.children, [], true)
|
||||||
|
|
||||||
# Combine text elements to single paragraph
|
# Combine text elements to single paragraph
|
||||||
formated_cell = combine_docx_elements(formated_cell)
|
formated_cell = combine_docx_elements(formated_cell)
|
||||||
|
formated_cell.each { |element| element[:style] = style } if style.present?
|
||||||
formated_cell
|
formated_cell
|
||||||
end.reject(&:blank?)
|
end.reject(&:blank?)
|
||||||
{ type: 'tr', data: cells }
|
{ type: 'tr', data: cells }
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<div class="template-editor-header">
|
<div class="template-editor-header">
|
||||||
<h1 class="title">
|
<h1 class="title">
|
||||||
<%= t('projects.reports.wizard.first_step.values_editor.title') %>
|
<% if @type == :pdf %>
|
||||||
|
<%= t('projects.reports.wizard.first_step.values_editor.title_pdf', template: @template_name) %>
|
||||||
|
<% else %>
|
||||||
|
<%= t('projects.reports.wizard.first_step.values_editor.title_docx', template: @template_name) %>
|
||||||
|
<% end %>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="collapse-buttons sci-btn-group pull-right">
|
<div class="collapse-buttons sci-btn-group pull-right">
|
||||||
<button class="btn btn-light collapse-all">
|
<button class="btn btn-light collapse-all">
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<% content_for :toc do %>
|
|
||||||
<h3 class="mb-4">Chapter 1</h3>
|
|
||||||
<div class="pl-6 flex flex-col gap-2">
|
|
||||||
<%= 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') %>
|
|
||||||
</div>
|
|
||||||
<h3 class="mb-4">Chapter 2</h3>
|
|
||||||
<div class="pl-6 flex flex-col gap-2">
|
|
||||||
<div>
|
|
||||||
<%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_3, label: 'Sub chapter 3 with inventory') %>
|
|
||||||
<div class="pl-6 mb-4">
|
|
||||||
<%= render Reports::RepositoriesInputComponent.new(report: report, name: 'custom_docx_sub_chapter_3_inventories[]', label: 'Inventories') %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<%= render Reports::CheckboxInputComponent.new(report: report, name: :custom_docx_sub_chapter_4, label: 'Sub chapter 4 with inventory') %>
|
|
||||||
<div class="pl-6 mb-4">
|
|
||||||
<%= render Reports::RepositoriesInputComponent.new(report: report, name: 'custom_docx_sub_chapter_4_inventories[]', label: 'Inventories') %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<%= 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') %>
|
|
||||||
</div>
|
|
||||||
<h3 class="mb-4">Chapter 3</h3>
|
|
||||||
<div class="pl-6 flex flex-col gap-2">
|
|
||||||
<%= 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') %>
|
|
||||||
<div class="pl-6 flex flex-col gap-2">
|
|
||||||
<%= 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') %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<h3 class="mb-4">Chapter 4</h3>
|
|
||||||
<div class="pl-6 flex flex-col gap-2">
|
|
||||||
<%= 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') %>
|
|
||||||
</div>
|
|
||||||
<h3 class="mb-4">Chapter 5</h3>
|
|
||||||
<% 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 %>
|
|
|
@ -1 +0,0 @@
|
||||||
Custom Template
|
|
|
@ -9,9 +9,11 @@
|
||||||
<span class="label label-warning"><%= t('search.index.archived') %></span>
|
<span class="label label-warning"><%= t('search.index.archived') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</h3>
|
</h3>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.experiment.user_time', code: experiment.code, timestamp: l(timestamp, format: :full)) %>
|
<%= t('projects.reports.elements.experiment.user_time', code: experiment.code, timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
<% if experiment.description.present? %>
|
<% if experiment.description.present? %>
|
||||||
<%= custom_auto_link(experiment.description, team: current_team, base64_encoded_imgs: export_all) %>
|
<%= custom_auto_link(experiment.description, team: current_team, base64_encoded_imgs: export_all) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -9,9 +9,12 @@
|
||||||
<span class="label label-warning"><%= t('search.index.archived') %></span>
|
<span class="label label-warning"><%= t('search.index.archived') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</h4>
|
</h4>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.module.user_time', code: my_module.code, timestamp: l(timestamp, format: :full)) %>
|
<%= t('projects.reports.elements.module.user_time', code: my_module.code, timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% unless @settings['exclude_task_metadata'] %>
|
||||||
<p class="module-start-date">
|
<p class="module-start-date">
|
||||||
<% if my_module.started_on.present? %>
|
<% if my_module.started_on.present? %>
|
||||||
<%= t('projects.reports.elements.module.started_on', started_on: l(my_module.started_on, format: :full)) %>
|
<%= t('projects.reports.elements.module.started_on', started_on: l(my_module.started_on, format: :full)) %>
|
||||||
|
@ -48,6 +51,7 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<% if my_module.description.present? %>
|
<% if my_module.description.present? %>
|
||||||
|
@ -90,10 +94,12 @@
|
||||||
|
|
||||||
<% if @settings.dig('task', 'file_results') %>
|
<% if @settings.dig('task', 'file_results') %>
|
||||||
<%= render partial: 'reports/elements/my_module_result_asset_element', locals: { result: result, report: report, export_all: export_all } %>
|
<%= render partial: 'reports/elements/my_module_result_asset_element', locals: { result: result, report: report, export_all: export_all } %>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.result.user_time', user: result.user.full_name, timestamp: l(result.created_at, format: :full)) %>
|
<%= t('projects.reports.elements.result.user_time', user: result.user.full_name, timestamp: l(result.created_at, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<div class="report-element-children">
|
<div class="report-element-children">
|
||||||
<% if @settings.dig('task', 'result_comments') %>
|
<% if @settings.dig('task', 'result_comments') %>
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
<%= t('projects.reports.elements.module.protocol.name') %>
|
<%= t('projects.reports.elements.module.protocol.name') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</h4>
|
</h4>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code, timestamp: l(protocol.created_at, format: :full)) %>
|
<%= t('projects.reports.elements.module.protocol.user_time', code: protocol.original_code, timestamp: l(protocol.created_at, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
<div class="row module-protocol-description">
|
<div class="row module-protocol-description">
|
||||||
<% if @settings.dig('task', 'protocol', 'description') && protocol.description.present? %>
|
<% if @settings.dig('task', 'protocol', 'description') && protocol.description.present? %>
|
||||||
<%= custom_auto_link(protocol.prepare_for_report(:description, export_all: export_all),
|
<%= custom_auto_link(protocol.prepare_for_report(:description, export_all: export_all),
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<%= t("projects.reports.elements.result_asset.user_time", user: result.user.full_name, timestamp: l(timestamp, format: :full)) %>
|
<%= 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) %>
|
<% if report.settings.dig(:task, :file_results_previews) && ActiveStorageFileUtil.previewable_document?(asset&.file&.blob) %>
|
||||||
<%= t('projects.reports.elements.result_asset.full_preview_attached') %>
|
<%= t('projects.reports.elements.result_asset.full_preview_attached') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -21,9 +21,11 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.result_table.user_time', timestamp: l(timestamp, format: :full)) %>
|
<%= t('projects.reports.elements.result_table.user_time', timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<input type="hidden" class="hot-table-contents" value="<%= table.contents_utf_8.gsub(/\</, '<').gsub(/\>/, '>') %>" />
|
<input type="hidden" class="hot-table-contents" value="<%= table.contents_utf_8.gsub(/\</, '<').gsub(/\>/, '>') %>" />
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
</em>
|
</em>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t("projects.reports.elements.result_text.user_time", timestamp: l(timestamp, format: :full)) %>
|
<%= t("projects.reports.elements.result_text.user_time", timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -8,11 +8,15 @@
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<h5 class="step-name">
|
<h5 class="step-name">
|
||||||
<b><%= t('projects.reports.elements.step.step_pos', pos: (step.position_plus_one)) %></b> <%= step.name %>
|
<b><%= t('projects.reports.elements.step.step_pos', pos: (step.position_plus_one)) %></b> <%= step.name %>
|
||||||
|
<% unless @settings['exclude_task_metadata'] %>
|
||||||
<%= step_status_label(step) %>
|
<%= step_status_label(step) %>
|
||||||
|
<% end %>
|
||||||
</h5>
|
</h5>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t("projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full)) %>
|
<%= t("projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-children">
|
<div class="report-element-children">
|
||||||
<% step.step_orderable_elements.order(:position).each do |e| %>
|
<% step.step_orderable_elements.order(:position).each do |e| %>
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
<span class="label label-warning"><%= t('search.index.archived') %></span>
|
<span class="label label-warning"><%= t('search.index.archived') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</h2>
|
</h2>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.project_header.user_time', code: project.code, timestamp: l(project.created_at, format: :full)) %>
|
<%= t('projects.reports.elements.project_header.user_time', code: project.code, timestamp: l(project.created_at, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% if defined?(children) %>
|
<% if defined?(children) %>
|
||||||
<div class="report-element-children">
|
<div class="report-element-children">
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
</em>
|
</em>
|
||||||
<% end %>
|
<% end %>
|
||||||
</span>
|
</span>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full)) %>
|
<%= t('projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<% if asset.previewable? && !asset.list? %>
|
<% if asset.previewable? && !asset.list? %>
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
team: current_team,
|
team: current_team,
|
||||||
base64_encoded_imgs: export_all) %>
|
base64_encoded_imgs: export_all) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t('projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full)) %>
|
<%= t('projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<% items.each do |item| %>
|
<% items.each do |item| %>
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t("projects.reports.elements.#{table_type}.user_time", timestamp: l(timestamp, format: :full)) %>
|
<%= t("projects.reports.elements.#{table_type}.user_time", timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<input type="hidden" class="hot-table-contents" value="<%= table.contents_utf_8.gsub(/\</, '<').gsub(/\>/, '>') %>" />
|
<input type="hidden" class="hot-table-contents" value="<%= table.contents_utf_8.gsub(/\</, '<').gsub(/\>/, '>') %>" />
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
</em>
|
</em>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<% unless @settings['exclude_timestamps'] %>
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<%= t("projects.reports.elements.step_text.user_time", timestamp: l(timestamp, format: :full)) %>
|
<%= t("projects.reports.elements.step_text.user_time", timestamp: l(timestamp, format: :full)) %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-element-body">
|
<div class="report-element-body">
|
||||||
<% if step_text.text.present? %>
|
<% if step_text.text.present? %>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<h1>
|
<h1>
|
||||||
<%= t('projects.reports.wizard.first_step.values_editor.no_values_title') %>
|
<% if type == :pdf %>
|
||||||
|
<%= t('projects.reports.wizard.first_step.values_editor.no_values_title_pdf', template: ) %>
|
||||||
|
<% else %>
|
||||||
|
<%= t('projects.reports.wizard.first_step.values_editor.no_values_title_docx', template: ) %>
|
||||||
|
<% end %>
|
||||||
</h1>
|
</h1>
|
||||||
<h3>
|
<h3>
|
||||||
<%= t('projects.reports.wizard.first_step.values_editor.no_values_description') %>
|
<%= t('projects.reports.wizard.first_step.values_editor.no_values_description') %>
|
||||||
|
|
|
@ -20,10 +20,11 @@
|
||||||
disable_on_load: report.settings[:template].blank? && report.new_record?,
|
disable_on_load: report.settings[:template].blank? && report.new_record?,
|
||||||
placeholder: t('projects.reports.wizard.first_step.select_template'),
|
placeholder: t('projects.reports.wizard.first_step.select_template'),
|
||||||
selected_template: report.settings[:template],
|
selected_template: report.settings[:template],
|
||||||
|
default_template: @default_template,
|
||||||
values_editor_path: reports_new_template_values_path(report_id: report.id)
|
values_editor_path: reports_new_template_values_path(report_id: report.id)
|
||||||
} %>
|
} %>
|
||||||
</div>
|
</div>
|
||||||
<div class='template-selector'>
|
<div class='template-selector <%= "hidden" unless custom_templates(Extends::DOCX_REPORT_TEMPLATES) %>'>
|
||||||
<%= label_tag :docxTemplateSelector, t('projects.reports.wizard.first_step.select_docx_template') %>
|
<%= label_tag :docxTemplateSelector, t('projects.reports.wizard.first_step.select_docx_template') %>
|
||||||
<%= select_tag :docxTemplateSelector,
|
<%= select_tag :docxTemplateSelector,
|
||||||
options_for_select(@docx_templates.invert, @active_docx_template),
|
options_for_select(@docx_templates.invert, @active_docx_template),
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
disable_on_load: report.settings[:docx_template].blank? && report.new_record?,
|
disable_on_load: report.settings[:docx_template].blank? && report.new_record?,
|
||||||
placeholder: t('projects.reports.wizard.first_step.select_docx_template'),
|
placeholder: t('projects.reports.wizard.first_step.select_docx_template'),
|
||||||
selected_template: report.settings[:docx_template],
|
selected_template: report.settings[:docx_template],
|
||||||
|
default_template: @default_docx_template,
|
||||||
values_editor_path: reports_new_docx_template_values_path(report_id: report.id)
|
values_editor_path: reports_new_docx_template_values_path(report_id: report.id)
|
||||||
} %>
|
} %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -55,7 +55,10 @@
|
||||||
</span><br>
|
</span><br>
|
||||||
<span class="repositories-items-description">
|
<span class="repositories-items-description">
|
||||||
<i class="sn-icon sn-icon-info"></i>
|
<i class="sn-icon sn-icon-info"></i>
|
||||||
<span><%= t("projects.reports.wizard.third_step.assigned_items_description") %></span>
|
<div class="flex-col font-normal">
|
||||||
|
<p><%= t("projects.reports.wizard.third_step.assigned_items_description") %></p>
|
||||||
|
<p><%= t("projects.reports.wizard.third_step.assigned_items_repository_items_description_html") %></p>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<ul class="collapse in" id="repositoriesContents">
|
<ul class="collapse in" id="repositoriesContents">
|
||||||
<li>
|
<li>
|
||||||
|
@ -68,13 +71,15 @@
|
||||||
<ul class="repositories-contents">
|
<ul class="repositories-contents">
|
||||||
<% @repositories.each do |repository| %>
|
<% @repositories.each do |repository| %>
|
||||||
<li>
|
<li>
|
||||||
|
<div class="flex items-center">
|
||||||
<span class="sci-checkbox-container">
|
<span class="sci-checkbox-container">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
class="sci-checkbox repositories-setting"
|
class="sci-checkbox repositories-setting"
|
||||||
value="<%= repository.is_a?(RepositorySnapshot) ? repository.parent_id : repository.id %>"
|
value="<%= repository.is_a?(RepositorySnapshot) ? repository.parent_id : repository.id %>"
|
||||||
<%= 'checked' if report.new_record? ||
|
<%= 'checked' if report.new_record? ||
|
||||||
@project_contents[:repositories].include?(repository.id) ||
|
@project_contents[:repositories].include?(repository.id) ||
|
||||||
(repository.is_a?(Repository) && repository.repository_snapshots.exists?(id: @project_contents[:repositories])) %> />
|
(repository.is_a?(Repository) && repository.repository_snapshots.exists?(id: @project_contents[:repositories])) ||
|
||||||
|
(repository.is_a?(RepositorySnapshot) && @project_contents[:repositories].include?(repository.parent_id)) %> />
|
||||||
<span class="sci-checkbox-label"></span>
|
<span class="sci-checkbox-label"></span>
|
||||||
</span>
|
</span>
|
||||||
<%= repository.name %>
|
<%= repository.name %>
|
||||||
|
@ -87,6 +92,37 @@
|
||||||
<%= t("projects.reports.wizard.third_step.deleted") %>
|
<%= t("projects.reports.wizard.third_step.deleted") %>
|
||||||
</span>
|
</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<select class="repository-columns"
|
||||||
|
id=<%= "repository-#{repository.id}" %>
|
||||||
|
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") %>"
|
||||||
|
data-select-all-button="<%= t("projects.reports.wizard.third_step.repository_column.select_deselect_all") %>"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
<% Report.default_repository_columns.each do |key, value| %>
|
||||||
|
<option value="<%= key %>"
|
||||||
|
selected-value="<%= report.settings.dig(:task,
|
||||||
|
:excluded_repository_columns,
|
||||||
|
(repository.is_a?(RepositorySnapshot) ? repository.parent_id : repository.id).to_s)
|
||||||
|
&.include?(key.to_s.to_i) ? '' : 'selected' %>"
|
||||||
|
>
|
||||||
|
<%= value %>
|
||||||
|
</option>
|
||||||
|
<% end %>
|
||||||
|
<% repository.repository_columns.find_each do |repository_column| %>
|
||||||
|
<option value="<%= repository_column.id %>"
|
||||||
|
selected-value="<%= report.settings.dig(:task,
|
||||||
|
:excluded_repository_columns,
|
||||||
|
(repository.is_a?(RepositorySnapshot) ? repository.parent_id : repository.id).to_s)
|
||||||
|
&.include?(repository_column.id.to_i) ? '' : 'selected' %>"
|
||||||
|
>
|
||||||
|
<%= repository_column.name %>
|
||||||
|
</option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -184,7 +220,7 @@
|
||||||
<%= t("projects.reports.wizard.third_step.additional_content") %>
|
<%= t("projects.reports.wizard.third_step.additional_content") %>
|
||||||
</span>
|
</span>
|
||||||
<ul class="additional-contents collapse in" id="additionalContents">
|
<ul class="additional-contents collapse in" id="additionalContents">
|
||||||
<li>
|
<li class="additional-content-task-activity">
|
||||||
<div class="select-all-container">
|
<div class="select-all-container">
|
||||||
<span class="sci-checkbox-container">
|
<span class="sci-checkbox-container">
|
||||||
<input type="checkbox" class="sci-checkbox task-setting" value="activities" <%= 'checked' if report.settings.dig(:task, :activities) %>/>
|
<input type="checkbox" class="sci-checkbox task-setting" value="activities" <%= 'checked' if report.settings.dig(:task, :activities) %>/>
|
||||||
|
@ -194,6 +230,26 @@
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="select-all-container">
|
||||||
|
<span class="sci-checkbox-container">
|
||||||
|
<input type="checkbox" class="sci-checkbox exclude-task-metadata-setting" value="exclude_task_metadata" <%= 'checked' if report.settings.dig(:exclude_task_metadata) %>/>
|
||||||
|
<span class="sci-checkbox-label"></span>
|
||||||
|
</span>
|
||||||
|
<%= t("projects.reports.wizard.third_step.exclude_task_metadata") %>
|
||||||
|
<div class="divider"></div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="select-all-container">
|
||||||
|
<span class="sci-checkbox-container">
|
||||||
|
<input type="checkbox" class="sci-checkbox exclude-timestamps-setting" value="exclude_timestamps" <%= 'checked' if report.settings.dig(:exclude_timestamps) %>/>
|
||||||
|
<span class="sci-checkbox-label"></span>
|
||||||
|
</span>
|
||||||
|
<%= t("projects.reports.wizard.third_step.exclude_timestamps") %>
|
||||||
|
<div class="divider"></div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
42
bin/load_report_templates
Executable file
42
bin/load_report_templates
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require 'httparty'
|
||||||
|
require 'zip'
|
||||||
|
|
||||||
|
template_zip_url_string = ENV.fetch('REPORT_TEMPLATES_ZIP_URL', nil)
|
||||||
|
|
||||||
|
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'
|
||||||
|
system("AWS_PAGER=\"\" aws s3api get-object --bucket #{template_zip_url.host} --key #{template_zip_url.path[1..]} #{ENV.fetch('APP_HOME', '.')}/app/views/reports/report_templates.zip")
|
||||||
|
File.read("#{ENV.fetch('APP_HOME', '.')}/app/views/reports/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 = 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.end_with?('/')
|
||||||
|
|
||||||
|
path.open('wb') do |f|
|
||||||
|
f.write(entry.get_input_stream.read)
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Extracted #{path}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -40,7 +40,6 @@ development:
|
||||||
|
|
||||||
# The password associated with the postgres role (username).
|
# The password associated with the postgres role (username).
|
||||||
# password: mysecretpassword
|
# password: mysecretpassword
|
||||||
|
|
||||||
# Connect on a TCP socket. Omitted by default since the client uses a
|
# 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 socket that doesn't need configuration. Windows does not have
|
||||||
# domain sockets, so uncomment these lines.
|
# domain sockets, so uncomment these lines.
|
||||||
|
|
|
@ -815,13 +815,15 @@ en:
|
||||||
report_description: "Report description (optional)"
|
report_description: "Report description (optional)"
|
||||||
report_description_placeholder: "In this report you can see..."
|
report_description_placeholder: "In this report you can see..."
|
||||||
values_editor:
|
values_editor:
|
||||||
title: "Enter template data"
|
title_pdf: "PDF %{template}"
|
||||||
|
title_docx: "DOCX %{template}"
|
||||||
description: "This template requires you to fill out additional information about this project. This is the only place you will be able to do so."
|
description: "This template requires you to fill out additional information about this project. This is the only place you will be able to do so."
|
||||||
header: "Header"
|
header: "Header"
|
||||||
cover: "Title page"
|
cover: "Title page"
|
||||||
footer: "Footer"
|
footer: "Footer"
|
||||||
toc: "Table of contents"
|
toc: "Table of contents"
|
||||||
no_values_title: "No additional data required"
|
no_values_title_pdf: "PDF %{template}: No additional data required"
|
||||||
|
no_values_title_docx: "DOCX %{template}: No additional data required"
|
||||||
no_values_description: "SciNote template doesn’t need any additional input for it to be successfully generated."
|
no_values_description: "SciNote template doesn’t need any additional input for it to be successfully generated."
|
||||||
second_step:
|
second_step:
|
||||||
select_project_content: "Select and reorder experiments and tasks"
|
select_project_content: "Select and reorder experiments and tasks"
|
||||||
|
@ -845,6 +847,7 @@ en:
|
||||||
step_comments: "Step comments"
|
step_comments: "Step comments"
|
||||||
assigned_items: "Assigned items"
|
assigned_items: "Assigned items"
|
||||||
assigned_items_description: "Inventories selected below will only contain the items that you assigned to the tasks directly."
|
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 <strong>only for the docx report.</strong> The stock management column by default reflects item consumption."
|
||||||
include_all_assigned_iitems: "Include all assigned items from the following inventories"
|
include_all_assigned_iitems: "Include all assigned items from the following inventories"
|
||||||
results: "Results"
|
results: "Results"
|
||||||
all_results: "Include all results elements"
|
all_results: "Include all results elements"
|
||||||
|
@ -863,8 +866,15 @@ en:
|
||||||
results_comments: "Result comments"
|
results_comments: "Result comments"
|
||||||
additional_content: "Additional content"
|
additional_content: "Additional content"
|
||||||
task_activity: "Include task activity"
|
task_activity: "Include task activity"
|
||||||
|
exclude_task_metadata: "Exclude task metadata"
|
||||||
|
exclude_timestamps: "Exclude timestamps"
|
||||||
archived: "[archived]"
|
archived: "[archived]"
|
||||||
deleted: "[deleted]"
|
deleted: "[deleted]"
|
||||||
|
repository_column:
|
||||||
|
select_deselect_all: 'Select/deselect all'
|
||||||
|
placeholder: 'Select columns'
|
||||||
|
all_selected: 'All columns selected'
|
||||||
|
selected: 'columns selected'
|
||||||
|
|
||||||
new:
|
new:
|
||||||
report_name_placeholder: "Name your report"
|
report_name_placeholder: "Name your report"
|
||||||
|
@ -967,6 +977,7 @@ en:
|
||||||
name: "%{repository} of task %{my_module}"
|
name: "%{repository} of task %{my_module}"
|
||||||
table_name: "%{name}"
|
table_name: "%{name}"
|
||||||
no_items: "No items"
|
no_items: "No items"
|
||||||
|
no_columns: "No columns selected"
|
||||||
result:
|
result:
|
||||||
user_time: "Added on %{timestamp} by %{user}."
|
user_time: "Added on %{timestamp} by %{user}."
|
||||||
result_asset:
|
result_asset:
|
||||||
|
|
Loading…
Add table
Reference in a new issue