Merge pull request #3403 from biosistemika/develop

Release 1.22.0
This commit is contained in:
Miha Mencin 2021-06-23 10:57:14 +02:00 committed by GitHub
commit 7ced8621e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
88 changed files with 659 additions and 1996 deletions

View file

@ -84,7 +84,7 @@ gem 'silencer' # Silence certain Rails logs
gem 'sneaky-save', git: 'https://github.com/einzige/sneaky-save'
gem 'turbolinks', '~> 5.1.1'
gem 'underscore-rails'
gem 'wicked_pdf', '~> 1.4.0'
gem 'wicked_pdf'
gem 'wkhtmltopdf-heroku', '2.12.5'
gem 'aws-sdk-rails'

View file

@ -210,7 +210,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.1.8)
concurrent-ruby (1.1.9)
crack (0.4.5)
rexml
crass (1.0.6)
@ -300,7 +300,7 @@ GEM
httparty (0.17.3)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (1.8.7)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
i18n-js (3.8.0)
i18n (>= 0.6.6)
@ -366,7 +366,7 @@ GEM
mini_magick (4.11.0)
mini_mime (1.0.2)
mini_portile2 (2.5.1)
minitest (5.14.3)
minitest (5.14.4)
momentjs-rails (2.17.1)
railties (>= 3.1)
msgpack (1.4.2)
@ -614,7 +614,7 @@ GEM
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
whacamole (1.2.0)
wicked_pdf (1.4.0)
wicked_pdf (2.1.0)
activesupport
wkhtmltopdf-heroku (2.12.5.0)
xpath (3.2.0)
@ -732,7 +732,7 @@ DEPENDENCIES
webmock
webpacker (~> 4.0.0)
whacamole
wicked_pdf (~> 1.4.0)
wicked_pdf
wkhtmltopdf-heroku (= 2.12.5)
yomu!

View file

@ -1 +1 @@
1.21.11
1.22.0

View file

@ -1020,19 +1020,21 @@ function reportHandsonTableConverter() {
});
// Project content
reportData.project_content = { experiments: [], tasks: {}, repositories: [] };
reportData.project_content = { experiments: [], repositories: [] };
$.each($('.project-contents-container .experiment-element'), function(i, experiment) {
let expCheckbox = $(experiment).find('.report-experiment-checkbox');
if (!expCheckbox.prop('checked') && !expCheckbox.prop('indeterminate')) return;
let experimentId = $(experiment).find('.report-experiment-checkbox').val();
reportData.project_content.tasks[experimentId] = [];
reportData.project_content.experiments.push(experimentId);
let experimentData = {};
experimentData.id = parseInt($(experiment).find('.report-experiment-checkbox').val(), 10);
experimentData.my_module_ids = [];
$.each($(experiment).find('.report-my-module-checkbox:checked'), function(j, myModule) {
reportData.project_content.tasks[experimentId].push(parseInt(myModule.value, 10));
experimentData.my_module_ids.push(parseInt(myModule.value, 10));
});
reportData.project_content.experiments.push(experimentData);
});
$.each($('.task-contents-container .repositories-contents .sci-checkbox:checked'), function(i, e) {
$.each($('.task-contents-container .repositories-contents .repositories-setting:checked'), function(i, e) {
reportData.project_content.repositories.push(parseInt(e.value, 10));
});

View file

@ -71,7 +71,7 @@
${I18n.t('projects.reports.index.previous_docx')})
</a>`;
}
return `<span class="processing-error">
return `<span class="processing-error docx">
<i class="fas fa-exclamation-triangle"></i>
${I18n.t('projects.reports.index.error')}${oldLink}
</span>`;
@ -101,7 +101,7 @@
${I18n.t('projects.reports.index.previous_pdf')})
</a>`;
}
return `<span class="processing-error">
return `<span class="processing-error pdf">
<i class="fas fa-exclamation-triangle"></i>
${I18n.t('projects.reports.index.error')}${oldLink}
</span>`;

View file

@ -226,26 +226,24 @@
clearDropdownResultsCallback(INVENTORY_PICKER);
}
function initializeSubmitAction() {
$('#content-reports-index').on('click', '#savePDFtoInventorySubmit', function() {
animateSpinner();
$.ajax({
url: $('#savePDFtoInventorySubmit').data('target-url'),
data: SELECTED_IDS,
type: 'POST',
success: function(data) {
animateSpinner(null, false);
HelperModule.flashAlertMsg(data.message, 'success');
$('#savePDFtoInventory').modal('hide');
},
error: function(xhr) {
animateSpinner(null, false);
HelperModule.flashAlertMsg(xhr.responseJSON.message, 'danger');
$('#savePDFtoInventory').modal('hide');
}
});
$('#content-reports-index').on('click', '#savePDFtoInventorySubmit', function() {
animateSpinner();
$.ajax({
url: $('#savePDFtoInventorySubmit').data('target-url'),
data: SELECTED_IDS,
type: 'POST',
success: function(data) {
animateSpinner(null, false);
HelperModule.flashAlertMsg(data.message, 'success');
$('#savePDFtoInventory').modal('hide');
},
error: function(xhr) {
animateSpinner(null, false);
HelperModule.flashAlertMsg(xhr.responseJSON.message, 'danger');
$('#savePDFtoInventory').modal('hide');
}
});
}
});
/*
* INITIALIZERS
@ -254,7 +252,6 @@
function initializeSavePDFtoInventoryModal() {
$('#content-reports-index').on('shown.bs.modal', '#savePDFtoInventory', function() {
initInventoriesSelectPicker();
initializeSubmitAction();
clearErrors();
// refresh the dropdown state
$('#selectInventory').parent().find('input').trigger('keyup');

View file

@ -152,7 +152,7 @@
padding-top: .25em;
&::after {
background: linear-gradient(to right, transparent, $color-white 50%);
background: linear-gradient(to right, $color-transparent, $color-white 50%);
bottom: .75em;
content: "";
height: 1.75em;
@ -270,7 +270,7 @@
&:hover {
.description-text::after {
background: linear-gradient(to right, transparent, $color-concrete 50%);
background: linear-gradient(to right, $color-transparent, $color-concrete 50%);
}
}
}
@ -323,7 +323,7 @@
}
.description-text::after {
background: linear-gradient(to right, transparent, $color-concrete 50%);
background: linear-gradient(to right, $color-transparent, $color-concrete 50%);
}
}
}
@ -341,7 +341,7 @@
&:hover {
.description-text::after {
background: linear-gradient(to right, transparent, $color-alto 50%);
background: linear-gradient(to right, $color-transparent, $color-alto 50%);
}
}
}

View file

@ -5,7 +5,7 @@ $color-alto: #d0d0d8;
$color-silver-chalice: #a0a0a8;
$color-volcano: #404048;
$color-black: #231f20;
$color-transparent: rgba(255, 255, 255, 0);
// Theme colors

View file

@ -76,7 +76,7 @@
margin-bottom: 0;
& > li > a {
padding: 8px 20px;
padding: 8px 38px;
}
}
@ -93,7 +93,17 @@
}
}
#support-link {
#knowledge-center-link {
.fas {
margin-left: -26px;
padding: 3px;
position: absolute
}
}
#support-link,
#knowledge-center-link {
color: $brand-primary;
}
}

View file

@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user!
helper_method :current_team
before_action :update_current_team, if: :user_signed_in?
before_action :set_date_format, if: :user_signed_in?
around_action :set_date_format, if: :user_signed_in?
around_action :set_time_zone, if: :current_user
layout 'main'
@ -102,7 +102,9 @@ class ApplicationController < ActionController::Base
end
def set_date_format
I18n.backend.date_format =
current_user.settings[:date_format] || Constants::DEFAULT_DATE_FORMAT
I18n.backend.date_format = current_user.settings[:date_format]
yield
ensure
I18n.backend.date_format = nil
end
end

View file

@ -1,186 +0,0 @@
# frozen_string_literal: true
module ReportActions
extend ActiveSupport::Concern
def in_params?(val)
params.include? val and params[val] == '1'
end
def generate_new_el(hide)
el = {}
el[:html] = render_to_string(
partial: 'reports/elements/new_element.html.erb',
locals: { hide: hide }
)
el[:children] = []
el[:new_element] = true
el
end
def generate_el(partial, locals)
el = {}
el[:html] = render_to_string(
partial: partial,
locals: locals
)
el[:children] = []
el[:new_element] = false
el
end
def generate_project_contents_json
res = []
if params.include? :modules
module_ids = (params[:modules].select { |_, p| p == '1' }).keys.collect(&:to_i)
# Get unique experiments from given modules
experiments = @project.experiments.distinct.joins(:my_modules).where('my_modules.id': module_ids)
experiments.each do |experiment|
res << generate_new_el(false)
el = generate_el(
'reports/elements/experiment_element.html.erb',
experiment: experiment
)
selected_modules = experiment.my_modules.includes(:tags).where(id: module_ids)
el[:children] = generate_experiment_contents_json(selected_modules)
res << el
end
end
res << generate_new_el(false)
res
end
def generate_experiment_contents_json(selected_modules)
res = []
selected_modules.order(:workflow_order).each do |my_module|
res << generate_new_el(false)
el = generate_el(
'reports/elements/my_module_element.html.erb',
my_module: my_module
)
el[:children] = generate_module_contents_json(my_module)
res << el
end
res << generate_new_el(false)
res
end
def generate_module_contents_json(my_module)
res = []
ReportExtends::MODULE_CONTENTS.each do |contents|
elements = []
contents.values.each do |element|
if contents.has_many
elements = params.select { |k| k.starts_with?("module_#{element}") }
elements = elements.select { |_, v| v == '1' }.keys
elements.map! { |el| el.gsub('module_', '') }.map! { |el| el.split('_') }
elements.map! { |el| [el[0].to_sym, el[1].to_i] }
break unless elements.empty?
else
present = in_params?("module_#{element}".to_sym) || in_params?(element.to_sym)
if present
elements << [element.to_sym, nil]
break
end
end
end
next if elements.empty?
elements.each do |_, el_id|
if contents.children
contents.collection(my_module, params).each do |report_el|
res << generate_new_el(false)
locals = contents.parse_locals([report_el])
locals[:element_id] = el_id if el_id
el = generate_el(
"reports/elements/my_module_#{contents.element.to_s.singularize}"\
"_element.html.erb",
locals
)
if :step.in? contents.locals
el[:children] = generate_step_contents_json(report_el)
elsif :result.in? contents.locals
el[:children] = generate_result_contents_json(report_el)
end
res << el
end
else
file_name = contents.file_name
res << generate_new_el(false)
locals = contents.parse_locals([my_module, :asc])
locals[:element_id] = el_id if el_id
res << generate_el(
"reports/elements/my_module_#{file_name}_element.html.erb",
locals
)
end
end
end
res << generate_new_el(false)
res
end
def generate_step_contents_json(step)
res = []
if in_params? :step_checklists
step.checklists.asc.each do |checklist|
res << generate_new_el(false)
res << generate_el(
'reports/elements/step_checklist_element.html.erb', checklist: checklist
)
end
end
if in_params? :step_assets
sort_value = step.current_view_state(current_user).state.dig('assets', 'sort')
step.assets.order(view_mode: :desc).sort_assets(sort_value).each do |asset|
res << generate_new_el(false)
res << generate_el(
'reports/elements/step_asset_element.html.erb', asset: asset
)
end
end
if in_params? :step_tables
step.tables.each do |table|
res << generate_new_el(false)
res << generate_el(
'reports/elements/step_table_element.html.erb', table: table
)
end
end
if in_params? :step_comments
res << generate_new_el(false)
res << generate_el(
'reports/elements/step_comments_element.html.erb', step: step, order: :asc
)
end
res << generate_new_el(false)
res
end
def generate_result_contents_json(result)
res = []
if in_params? :result_comments
res << generate_new_el(true)
res << generate_el(
'reports/elements/result_comments_element.html.erb', result: result, order: :asc
)
else
res << generate_new_el(false)
end
res
end
def elements_empty?(elements)
return true if elements.blank? || elements.count.zero?
if elements.count == 1
el = elements[0]
return true if el.include?(:new_element) && el[:new_element]
return false
end
false
end
end

View file

@ -2,6 +2,7 @@ class ReportsController < ApplicationController
include TeamsHelper
include ReportActions
include ReportsHelper
include StringUtility
BEFORE_ACTION_METHODS = %i(
create
@ -9,23 +10,14 @@ class ReportsController < ApplicationController
update
generate_pdf
generate_docx
save_modal
new_template_values
project_contents
experiment_contents_modal
module_contents_modal
step_contents_modal
result_contents_modal
experiment_contents
module_contents
step_contents
result_contents
).freeze
before_action :load_vars, only: %i(edit update document_preview generate_pdf generate_docx status
save_pdf_to_inventory_modal save_pdf_to_inventory_item)
before_action :load_vars_nested, only: BEFORE_ACTION_METHODS
before_action :load_visible_projects, only: %i(new edit)
before_action :load_wizard_vars, only: %i(new edit)
before_action :load_available_repositories, only: %i(index save_pdf_to_inventory_modal available_repositories)
before_action :check_manage_permissions, only: BEFORE_ACTION_METHODS
@ -51,7 +43,6 @@ class ReportsController < ApplicationController
# Report grouped by modules
def new
@templates = Extends::REPORT_TEMPLATES
@repositories = Repository.accessible_by_teams(current_team).active.select(:id, :name).order(:name)
@report = current_team.reports.new
end
@ -112,9 +103,7 @@ class ReportsController < ApplicationController
def edit
@edit = true
@templates = Extends::REPORT_TEMPLATES
@active_template = @report.settings[:template]
@repositories = Repository.accessible_by_teams(current_team).active.select(:id, :name).order(:name)
@report.settings = Report::DEFAULT_SETTINGS if @report.settings.blank?
@project_contents = {
@ -128,7 +117,9 @@ class ReportsController < ApplicationController
# Updating existing report from the _save modal of the new page
def update
@report.last_modified_by = current_user
@report.assign_attributes(report_params)
@report.assign_attributes(
report_params.merge(project_id: @project.id)
)
ReportActions::ReportContent.new(
@report,
@ -205,6 +196,8 @@ class ReportsController < ApplicationController
format.json do
@report.docx_processing!
log_activity(:generate_docx_report)
ensure_report_template!
Reports::DocxJob.perform_later(@report.id, current_user, root_url)
render json: {
message: I18n.t('projects.reports.index.generation.accepted_message')
@ -245,58 +238,6 @@ class ReportsController < ApplicationController
render json: { message: e.message }, status: :internal_server_error
end
# Modal for saving the existsing/new report
def save_modal
# Assume user is updating existing report
@report = @project.reports.find_by_id(params[:id])
@method = :put
# Case when saving a new report
if @report.blank?
@report = Report.new
@method = :post
@url = project_reports_path(@project, format: :json)
else
@url = project_report_path(@project, @report, format: :json)
end
render_403 and return unless params.include? :contents
@report_contents = params[:contents]
respond_to do |format|
format.json do
render json: {
html: render_to_string(
partial: 'reports/new/modal/save.html.erb'
)
}
end
end
end
# Experiment for adding contents into experiment element
def experiment_contents_modal
experiment = @project.experiments.find_by_id(params[:experiment_id])
respond_to do |format|
if experiment.blank?
format.json do
render json: {}, status: :not_found
end
else
format.json do
render json: {
html: render_to_string(
partial: 'reports/new/modal/experiment_contents.html.erb',
locals: { project: @project, experiment: experiment }
)
}
end
end
end
end
# Modal for adding contents into module element
def module_contents_modal
my_module = MyModule.find_by_id(params[:my_module_id])
@ -375,105 +316,6 @@ class ReportsController < ApplicationController
}
end
def experiment_contents
experiment = @project.experiments.find_by(id: params[:id])
module_ids = (params[:modules].select { |_, p| p == '1' }).keys.collect(&:to_i)
selected_modules = experiment.my_modules.where(id: module_ids)
respond_to do |format|
if experiment.blank?
format.json { render json: {}, status: :not_found }
elsif selected_modules.blank?
format.json { render json: {}, status: :no_content }
else
elements = generate_experiment_contents_json(selected_modules)
end
if elements_empty? elements
format.json { render json: {}, status: :no_content }
else
format.json do
render json: {
status: :ok,
elements: elements
}
end
end
end
end
def module_contents
my_module = MyModule.find_by_id(params[:id])
return render_403 unless my_module.experiment.project == @project
respond_to do |format|
if my_module.blank?
format.json { render json: {}, status: :not_found }
else
elements = generate_module_contents_json(my_module)
if elements_empty? elements
format.json { render json: {}, status: :no_content }
else
format.json do
render json: {
status: :ok,
elements: elements
}
end
end
end
end
end
def step_contents
step = Step.find_by_id(params[:id])
return render_403 unless step.my_module.experiment.project == @project
respond_to do |format|
if step.blank?
format.json { render json: {}, status: :not_found }
else
elements = generate_step_contents_json(step)
if elements_empty? elements
format.json { render json: {}, status: :no_content }
else
format.json {
render json: {
status: :ok,
elements: elements
}
}
end
end
end
end
def result_contents
result = Result.find_by_id(params[:id])
return render_403 unless result.my_module.experiment.project == @project
respond_to do |format|
if result.blank?
format.json { render json: {}, status: :not_found }
else
elements = generate_result_contents_json(result)
if elements_empty? elements
format.json { render json: {}, status: :no_content }
else
format.json {
render json: {
status: :ok,
elements: elements
}
}
end
end
end
end
def available_repositories
render json: { results: @available_repositories }, status: :ok
end
@ -490,7 +332,6 @@ class ReportsController < ApplicationController
private
include StringUtility
AvailableRepository = Struct.new(:id, :name)
def load_vars
@ -505,12 +346,14 @@ class ReportsController < ApplicationController
render_403 unless can_read_project?(@project)
end
def check_manage_permissions
render_403 unless can_manage_reports?(@project.team)
end
def load_visible_projects
render_404 unless current_team
def load_wizard_vars
@templates = Extends::REPORT_TEMPLATES
live_repositories = Repository.accessible_by_teams(current_team)
snapshots_of_deleted = RepositorySnapshot.left_outer_joins(:original_repository)
.where(team: current_team)
.where.not(original_repository: live_repositories)
.select('DISTINCT ON ("repositories"."parent_id") "repositories".*')
@repositories = (live_repositories + snapshots_of_deleted).sort_by { |r| r.name.downcase }
@visible_projects = Project.active
.viewable_by_user(current_user, current_team)
.joins(experiments: :my_modules)
@ -519,6 +362,10 @@ class ReportsController < ApplicationController
.select(:id, :name)
end
def check_manage_permissions
render_403 unless can_manage_reports?(@project.team)
end
def load_available_repositories
@available_repositories = []
repositories = Repository.active
@ -562,6 +409,15 @@ class ReportsController < ApplicationController
@report.pdf_processing!
log_activity(:generate_pdf_report)
ensure_report_template!
Reports::PdfJob.perform_later(@report.id, current_user)
end
def ensure_report_template!
return if @report.settings['template'].present?
@report.settings['template'] = 'scinote_template'
@report.save
end
end

View file

@ -3,99 +3,24 @@
module ReportsHelper
include StringUtility
def render_new_element(hide)
render partial: 'reports/elements/new_element.html.erb',
locals: { hide: hide }
end
def render_report_element(element, provided_locals = nil)
# Determine partial
file_name = element.type_of
if element.type_of.in? ReportExtends::MY_MODULE_CHILDREN_ELEMENTS
file_name = "my_module_#{element.type_of.singularize}"
end
view = "reports/elements/#{file_name}_element.html.erb"
view = "reports/elements/#{element.type_of}_element.html.erb"
# Set locals
locals = provided_locals.nil? ? {} : provided_locals.clone
children_html = ''.html_safe
# First, recursively render element's children
if element.comments? || element.project_header?
# Render no children
elsif element.result?
# Special handling for result comments
if element.children.active.present?
children_html.safe_concat render_new_element(true)
element.children.active.each do |child|
children_html
.safe_concat render_report_element(child, provided_locals)
end
else
children_html.safe_concat render_new_element(false)
if element.children.active.present?
element.children.active.each do |child|
children_html.safe_concat render_report_element(child, provided_locals)
end
else
if element.children.active.present?
element.children.active.each do |child|
children_html.safe_concat render_new_element(false)
children_html
.safe_concat render_report_element(child, provided_locals)
end
end
children_html.safe_concat render_new_element(false)
end
locals[:report_element] = element
locals[:children] = children_html
if provided_locals[:export_all]
# Set path and filename locals for files and tables in export all ZIP
if element['type_of'] == 'my_module_repository'
obj_id = element[:repository_id]
elsif element['type_of'].in? %w(step_asset step_table result_asset
result_table)
parent_el = ReportElement.find(element['parent_id'])
parent_type = parent_el[:type_of]
parent = parent_type.singularize.classify.constantize
.find(parent_el["#{parent_type}_id"])
if parent.class == Step
obj_id = if element['type_of'] == 'step_asset'
element[:asset_id]
elsif element['type_of'] == 'step_table'
element[:table_id]
end
elsif parent.class == MyModule
result = Result.find(element[:result_id])
obj_id = if element['type_of'] == 'result_asset'
result.asset.id
elsif element['type_of'] == 'result_table'
result.table.id
end
end
end
if obj_id
file = provided_locals[:obj_filenames][element['type_of'].to_sym][obj_id]
locals[:path] = {
file: file[:file].sub(%r{/usr/src/app/tmp/temp-zip-\d+/}, ''),
preview: file[:preview]&.sub(%r{/usr/src/app/tmp/temp-zip-\d+/}, '')
}
locals[:filename] = locals[:path][:file].split('/').last
end
end
# ReportExtends is located in config/initializers/extends/report_extends.rb
ReportElement.type_ofs.keys.each do |type|
next unless element.public_send("#{type}?")
element.element_references.each do |el_ref|
locals[el_ref.class.name.underscore.to_sym] = el_ref
end
end
(render partial: view, locals: locals).html_safe
render partial: view, locals: locals
end
# "Hack" to omit file preview URL because of WKHTML issues
@ -106,46 +31,15 @@ module ReportsHelper
image_tag('icon_small/missing.png')
end
# "Hack" to load Glyphicons css directly from the CDN
# site so they work in report
def bootstrap_cdn_link_tag
specs = Gem.loaded_specs['bootstrap-sass']
return '' unless specs.present?
stylesheet_link_tag("http://netdna.bootstrapcdn.com/bootstrap/" \
"#{specs.version.version}/css/bootstrap.min.css",
media: 'all')
end
def font_awesome_cdn_link_tag
stylesheet_link_tag(
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/fontawesome.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/regular.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/solid.min.css'
)
end
def assigned_repository_or_snapshot(my_module, element_id, snapshot, repository)
if element_id
repository = Repository.accessible_by_teams(my_module.experiment.project.team).find_by(id: element_id)
# Check for default set snapshots when repository still exists
if repository
selected_snapshot = repository.repository_snapshots.where(my_module: my_module).find_by(selected: true)
repository = selected_snapshot if selected_snapshot
end
repository ||= RepositorySnapshot.joins(my_module: { experiment: :project })
.where(my_module: { experiments: { project: my_module.experiment.project } })
.find_by(id: element_id)
def assigned_repository_or_snapshot(my_module, repository)
if repository.is_a?(RepositorySnapshot)
return my_module.repository_snapshots.find_by(parent_id: repository.parent_id, selected: true)
end
repository || snapshot
end
def assigned_repositories_in_project_list(project)
live_repositories = Repository.assigned_to_project(project)
snapshots = RepositorySnapshot.of_unassigned_from_project(project)
return nil unless my_module.assigned_repositories.exists?(id: repository.id)
snapshots.each { |snapshot| snapshot.name = "#{snapshot.name} #{t('projects.reports.index.deleted')}" }
(live_repositories + snapshots).sort_by { |r| r.name.downcase }
selected_snapshot = repository.repository_snapshots.find_by(my_module: my_module, selected: true)
selected_snapshot || repository
end
def step_status_label(step)
@ -159,18 +53,12 @@ module ReportsHelper
"<span class=\"label step-label-#{style}\">[#{text}]</span>".html_safe
end
# Fixes issues with avatar images in reports
def fix_smart_annotation_image(html)
html_doc = Nokogiri::HTML(html)
html_doc.search('.atwho-user-popover').each do |el|
text = el.content
el.replace("<a href='#' style='margin-left: 5px'>#{text}</a>")
end
html_doc.search('[ref="missing-img"]').each do |el|
tag = wicked_pdf_image_tag('icon_small/missing.png')
el.replace(tag)
end
html_doc.to_s
def font_awesome_cdn_link_tag
stylesheet_link_tag(
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/fontawesome.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/regular.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/solid.min.css'
)
end
def filter_steps_for_report(steps, settings)
@ -215,19 +103,4 @@ module ReportsHelper
.where(id: report.report_elements.my_module.select(:my_module_id))
repository.repository_rows.joins(:my_modules).where(my_modules: my_modules)
end
private
def obj_name_to_filename(obj, filename_suffix = '')
obj_name = if obj.class == Asset
obj_name, extension = obj.file_name.split('.')
extension&.prepend('.')
obj_name
elsif obj.class.in? [Table, Result, Repository]
extension = '.csv'
obj.name.present? ? obj.name : obj.class.name
end
obj_name = to_filesystem_name(obj_name)
obj_name + "#{filename_suffix}#{extension}"
end
end

View file

@ -37,7 +37,7 @@ module Reports
report = Report.find(report_id)
file = Tempfile.new(['report', '.docx'])
begin
I18n.backend.date_format = user.settings[:date_format] || Constants::DEFAULT_DATE_FORMAT
I18n.backend.date_format = user.settings[:date_format]
docx = Caracal::Document.new(file.path)
Reports::Docx.new(report, docx, user: user, scinote_url: root_url).draw
docx.save
@ -52,9 +52,11 @@ module Reports
report_link: "<a href='#{report_path}'>#{sanitize_input(report.name)}</a>",
team_name: sanitize_input(report.team.name))
)
Reports::DocxPreviewJob.perform_now(report.id)
notification.create_user_notification(user)
ensure
I18n.backend.date_format = Constants::DEFAULT_DATE_FORMAT
I18n.backend.date_format = nil
file.close
file.unlink
end

View file

@ -0,0 +1,53 @@
# frozen_string_literal: true
# Provides asynchronous generation of image previews for ActiveStorage::Blob records.
module Reports
class DocxPreviewJob < ApplicationJob
queue_as :reports
discard_on StandardError do |job, error|
Rails.logger.error(
"Couldn't generate PDF preview for DOCX Report with id: #{job.arguments.first}. Error:\n #{error}"
)
end
discard_on ActiveRecord::RecordNotFound
def perform(report_id)
report = Report.find(report_id)
blob = report.docx_file.blob
blob.open(tmpdir: tempdir) do |input|
work_dir = File.dirname(input.path)
preview_filename = "#{File.basename(input.path, '.*')}.pdf"
preview_file = File.join(work_dir, preview_filename)
Rails.logger.info "Starting preparing document preview for file #{blob.filename.sanitized}..."
ActiveRecord::Base.transaction do
success = system(
libreoffice_path, '--headless', '--invisible', '--convert-to', 'pdf', '--outdir', work_dir, input.path
)
unless success && File.file?(preview_file)
raise StandardError, "There was an error generating PDF preview, blob id: #{blob.id}"
end
ActiveRecord::Base.no_touching do
report.docx_preview_file.attach(io: File.open(preview_file), filename: "#{blob.filename.base}.pdf")
end
Rails.logger.info("Finished preparing PDF preview for file #{blob.filename.sanitized}.")
end
ensure
File.delete(preview_file) if File.file?(preview_file)
end
end
private
def tempdir
Rails.root.join('tmp')
end
def libreoffice_path
ENV['LIBREOFFICE_PATH'] || 'soffice'
end
end
end

View file

@ -6,6 +6,8 @@ module Reports
include InputSanitizeHelper
include ReportsHelper
PDFUNITE_ENCRYPTED_PDF_ERROR_STRING = 'Unimplemented Feature: Could not merge encrypted files'
queue_as :reports
discard_on StandardError do |job, error|
@ -49,7 +51,7 @@ module Reports
raise StandardError, 'Report template not found!' if template.blank?
I18n.backend.date_format = user.settings[:date_format] || Constants::DEFAULT_DATE_FORMAT
I18n.backend.date_format = user.settings[:date_format]
ActionController::Renderer::RACK_KEY_TRANSLATION['warden'] ||= 'warden'
proxy = Warden::Proxy.new({}, Warden::Manager.new({}))
proxy.set_user(user, scope: :user, store: false)
@ -58,10 +60,10 @@ module Reports
file << renderer.render(
pdf: 'report', header: { html: { template: "reports/templates/#{template}/header",
locals: { report: report, user: user },
locals: { report: report, user: user, logo: report_logo },
layout: 'reports/footer_header.html.erb' } },
footer: { html: { template: "reports/templates/#{template}/footer",
locals: { report: report, user: user },
locals: { report: report, user: user, logo: report_logo },
layout: 'reports/footer_header.html.erb' } },
assigns: { settings: report.settings },
locals: { report: report },
@ -89,7 +91,7 @@ module Reports
)
notification.create_user_notification(user)
ensure
I18n.backend.date_format = Constants::DEFAULT_DATE_FORMAT
I18n.backend.date_format = nil
file.close(true)
end
end
@ -119,12 +121,22 @@ module Reports
def merge_pdf_files(file, report_file)
merged_file = Tempfile.new(['report', '.pdf'], binmode: true)
success = system(
_output, error, status = Open3.capture3(
'pdfunite', report_file.path, file.path, merged_file.path
)
unless success && File.file?(merged_file)
raise StandardError, 'There was an error merging report and PDF file preview'
# don't raise error if the issue was an encrypted pdf, which pdfunite doesn't support
if error.include?(PDFUNITE_ENCRYPTED_PDF_ERROR_STRING)
Rails.logger.warn("Cannot merge encrypted PDF #{file.path}, skipping!")
file.close(true)
merged_file.close(true)
# return the report file unchanged, as no merge was done
return report_file
elsif !status.success? || !File.file?(merged_file)
raise StandardError, "There was an error merging report and PDF file preview (#{error})"
end
file.close(true)
@ -152,7 +164,7 @@ module Reports
title_page << renderer.render(
pdf: 'report', inline: renderer.render_to_string("reports/templates/#{template}/cover.html.erb",
layout: false,
locals: { report: report, total_pages: total_pages.to_i }),
locals: { report: report, total_pages: total_pages.to_i, logo: report_logo }),
disable_javascript: false,
template: 'reports/report.pdf.erb'
)
@ -170,5 +182,10 @@ module Reports
merged_file
end
def report_logo
'logo.png'
end
end
end

View file

@ -216,7 +216,7 @@ class Project < ApplicationRecord
def assigned_repositories_and_snapshots
live_repositories = Repository.assigned_to_project(self)
snapshots = RepositorySnapshot.of_unassigned_from_project(self)
snapshots = RepositorySnapshot.assigned_to_project(self)
(live_repositories + snapshots).sort_by { |r| r.name.downcase }
end
@ -267,15 +267,15 @@ class Project < ApplicationRecord
ActionController::Renderer::RACK_KEY_TRANSLATION['warden'] ||= 'warden'
proxy = Warden::Proxy.new({}, Warden::Manager.new({}))
proxy.set_user(user, scope: :user, store: false)
ApplicationController.renderer.defaults[:http_host] = Rails.application.routes.default_url_options[:host]
renderer = ApplicationController.renderer.new(warden: proxy)
report = Report.generate_whole_project_report(self, user, team)
page_html_string =
renderer.render 'reports/new_old.html.erb',
locals: { export_all: true,
obj_filenames: obj_filenames },
assigns: { project: self, report: report }
renderer.render 'reports/export.html.erb',
locals: { report: report, export_all: true },
assigns: { settings: report.settings, obj_filenames: obj_filenames }
parsed_page_html = Nokogiri::HTML(page_html_string)
parsed_html = parsed_page_html.at_css('#report-content')

View file

@ -11,6 +11,7 @@ class Report < ApplicationRecord
# ActiveStorage configuration
has_one_attached :pdf_file
has_one_attached :docx_file
has_one_attached :docx_preview_file
auto_strip_attributes :name, :description, nullify: false
validates :name,
@ -93,61 +94,27 @@ class Report < ApplicationRecord
report_elements.active.where(parent: nil).order(:position)
end
# Clean report elements from report
# the function runs before the report is edit
def cleanup_report
report_elements.each(&:clean_removed_or_archived_elements)
end
def self.generate_whole_project_report(project, current_user, current_team)
# report_contents = gen_element_content(project, Extends::EXPORT_ALL_PROJECT_ELEMENTS)
content = {
'experiments' => [],
'tasks' => {},
'repositories' => Repository.accessible_by_teams(project.team).pluck(:id)
'repositories' => project.assigned_repositories_and_snapshots.pluck(:id)
}
project.experiments.includes(:my_modules).each do |experiment|
content['experiments'].push(experiment.id)
content['tasks'][experiment.id] = experiment.my_modules.pluck(:id)
content['experiments'].push(
{ id: experiment.id, my_module_ids: experiment.my_module_ids }
)
end
report = Report.new
report.name = loop do
dummy_name = SecureRandom.hex(10)
break dummy_name unless Report.where(name: dummy_name).exists?
break dummy_name unless Report.exists?(name: dummy_name)
end
report.project = project
report.user = current_user
report.team = current_team
report.last_modified_by = current_user
ReportActions::ReportContent.new(report, content, {}, current_user).save_with_content
# report.save_with_contents(report_contents)
report
end
def self.gen_element_content(parent, children)
elements = []
children.each do |element|
element_hash = lambda { |object|
hash_object = {
'type_of' => element[:type_of] || element[:type_of_lambda].call(object),
'id' => { element[:id_key] => object.id },
'sort_order' => element[:sort_order],
'children' => gen_element_content(object, element[:children] || [])
}
hash_object['id'][element[:parent_id_key]] = parent.id if element[:parent_id_key]
hash_object
}
if element[:relation]
(element[:relation].inject(parent) { |p, method| p.public_send(method) }).each do |child|
elements.push(element_hash.call(child))
end
else
elements.push(element_hash.call(parent))
end
end
elements
end
end

View file

@ -12,7 +12,6 @@ class ReportElement < ApplicationRecord
validates :position, presence: true
validates :report, presence: true
validates :type_of, presence: true
validate :has_one_of_referenced_elements
belongs_to :report, inverse_of: :report_elements
@ -33,71 +32,7 @@ class ReportElement < ApplicationRecord
belongs_to :checklist, inverse_of: :report_elements, optional: true
belongs_to :asset, inverse_of: :report_elements, optional: true
belongs_to :table, inverse_of: :report_elements, optional: true
belongs_to :repository, inverse_of: :report_elements, optional: true,
foreign_key: :repository_id, class_name: 'RepositoryBase'
belongs_to :repository, inverse_of: :report_elements, optional: true, class_name: 'RepositoryBase'
scope :active, -> { where(type_of: ReportExtends::ACTIVE_REPORT_ELEMENTS) }
def result?
result_asset? or result_table? or result_text?
end
def comments?
step_comments? or result_comments?
end
# Get the referenced elements (previously, element's type_of must be set)
def element_references
ReportExtends::ELEMENT_REFERENCES.each do |el_ref|
if el_ref.check(self)
return el_ref.elements.map { |el| eval(el.gsub('_id', '')) }
end
end
end
# Set the element references (previously, element's type_of must be set)
def set_element_references(ref_ids)
ReportExtends::SET_ELEMENT_REFERENCES_LIST.each do |el_ref|
check = el_ref.check(self)
next unless check
el_ref.elements.each do |element|
public_send("#{element}=", ref_ids[element])
end
break
end
end
# removes element that are archived or deleted
def clean_removed_or_archived_elements
parent_model = ''
%w(project
experiment
my_module
step
result
checklist
asset
table
repository)
.each do |el|
parent_model = el if send el
end
if parent_model == 'experiment'
destroy unless send(parent_model).project == report.project
else
destroy unless (send(parent_model).active? rescue send(parent_model))
end
end
private
def has_one_of_referenced_elements
element_references.each do |el|
next unless el.nil?
errors.add(:base,
'Report element doesn\'t have correct element references.')
break
end
end
scope :active, -> { where(type_of: Extends::ACTIVE_REPORT_ELEMENTS) }
end

View file

@ -86,9 +86,9 @@ class Repository < RepositoryBase
repository_rows = readable_rows.where(id: repository_row_matches)
repository_rows = repository_rows.or(readable_rows.where(id: matched_by_user))
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |field, include_hash|
custom_cell_matches = readable_rows.joins(repository_cells: include_hash)
.where_attributes_like(field, query, options)
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |_data_type, config|
custom_cell_matches = repository_rows.joins(repository_cells: config[:includes])
.where_attributes_like(config[:field], query, options)
repository_rows = repository_rows.or(readable_rows.where(id: custom_cell_matches))
end

View file

@ -26,6 +26,12 @@ class RepositorySnapshot < RepositoryBase
.order(:parent_id, updated_at: :desc)
}
scope :assigned_to_project, lambda { |project|
where(team: project.team)
.joins(my_module: { experiment: :project })
.where(my_module: { experiments: { project: project } })
}
def self.create_preliminary(repository, my_module, created_by = nil)
created_by ||= repository.created_by
repository_snapshot = repository.dup.becomes(RepositorySnapshot)

View file

@ -49,8 +49,7 @@ class TeamZipExport < ZipExport
project_path = make_model_dir(team_path, p, idx)
project_name = project_path.split('/')[-1]
obj_filenames = { my_module_repository: {}, step_asset: {},
step_table: {}, result_asset: {}, result_table: {} }
obj_filenames = { repositories: {}, assets: {}, tables: {} }
# Change current dir for correct generation of relative links
Dir.chdir(project_path)
@ -63,7 +62,9 @@ class TeamZipExport < ZipExport
# Iterate through every inventory repo and save it to CSV
repositories.each_with_index do |repo, repo_idx|
obj_filenames[:my_module_repository][repo.id] = {
next if obj_filenames[:repositories][repo.id].present?
obj_filenames[:repositories][repo.id] = {
file: save_inventories_to_csv(inventories, repo, repo_idx)
}
end
@ -88,16 +89,16 @@ class TeamZipExport < ZipExport
# Export protocols
steps = my_module.protocols.map(&:steps).flatten
obj_filenames[:step_asset].merge!(
obj_filenames[:assets].merge!(
export_assets(StepAsset.where(step: steps), :step, protocol_path)
)
obj_filenames[:step_table].merge!(
obj_filenames[:tables].merge!(
export_tables(StepTable.where(step: steps), :step, protocol_path)
)
# Export results
[false, true].each do |archived|
obj_filenames[:result_asset].merge!(
obj_filenames[:assets].merge!(
export_assets(
ResultAsset.where(result: my_module.results.where(archived: archived)),
:result,
@ -108,7 +109,7 @@ class TeamZipExport < ZipExport
end
[false, true].each do |archived|
obj_filenames[:result_table].merge!(
obj_filenames[:tables].merge!(
export_tables(
ResultTable.where(result: my_module.results.where(archived: archived)),
:result,

View file

@ -25,9 +25,11 @@ Canaid::Permissions.register_for(Asset) do
when Result
can_manage_result?(object)
when RepositoryCell
return false if object.repository_column.repository.is_a?(RepositorySnapshot)
can_manage_repository?(user, object.repository_column.repository)
if object.repository_column.repository.is_a?(RepositorySnapshot)
false
else
can_manage_repository?(user, object.repository_column.repository)
end
end
end
end

View file

@ -9,7 +9,7 @@ module Api
belongs_to :project_folder, serializer: ProjectFolderSerializer
def start_date
I18n.l(object.created_at, format: :full)
object.created_at
end
end
end

View file

@ -3,11 +3,33 @@
module Api
module V1
class ReportSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
type :reports
attributes :id, :name, :description
attribute :pdf_file_size, if: -> { object.pdf_file.attached? }
attribute :pdf_file_url, if: -> { object.pdf_file.attached? }
attribute :docx_file_size, if: -> { object.docx_file.attached? }
attribute :docx_file_url, if: -> { object.docx_file.attached? }
belongs_to :user, serializer: UserSerializer
belongs_to :project, serializer: ProjectSerializer,
unless: -> { instance_options[:hide_project] }
def pdf_file_size
object.pdf_file.blob.byte_size
end
def pdf_file_url
rails_blob_path(object.pdf_file, disposition: 'attachment')
end
def docx_file_size
object.docx_file.blob.byte_size
end
def docx_file_url
rails_blob_path(object.docx_file, disposition: 'attachment')
end
end
end
end

View file

@ -3,7 +3,14 @@
module Api
module V1
class RepositoryDateRangeValueSerializer < ActiveModel::Serializer
attribute :formatted, key: :date_range
attribute :date_range
def date_range
{
from: object.start_time.to_date,
to: object.end_time.to_date
}
end
end
end
end

View file

@ -3,7 +3,14 @@
module Api
module V1
class RepositoryDateTimeRangeValueSerializer < ActiveModel::Serializer
attribute :formatted, key: :date_time_range
attribute :date_time_range
def date_time_range
{
from: object.start_time,
to: object.end_time
}
end
end
end
end

View file

@ -3,7 +3,11 @@
module Api
module V1
class RepositoryDateTimeValueSerializer < ActiveModel::Serializer
attribute :formatted, key: :date_time
attribute :date_time
def date_time
object.data
end
end
end
end

View file

@ -3,7 +3,11 @@
module Api
module V1
class RepositoryDateValueSerializer < ActiveModel::Serializer
attribute :formatted, key: :date
attribute :date
def date
object.data.to_date
end
end
end
end

View file

@ -3,7 +3,14 @@
module Api
module V1
class RepositoryTimeRangeValueSerializer < ActiveModel::Serializer
attribute :formatted, key: :time_range
attribute :time_range
def time_range
{
from: object.start_time.strftime('%H:%M:%S.%3NZ'),
to: object.start_time.strftime('%H:%M:%S.%3NZ')
}
end
end
end
end

View file

@ -3,7 +3,11 @@
module Api
module V1
class RepositoryTimeValueSerializer < ActiveModel::Serializer
attribute :formatted, key: :time
attribute :time
def time
object.data.strftime('%H:%M:%S.%3NZ')
end
end
end
end

View file

@ -3,6 +3,7 @@
module ReportActions
class ReportContent
include Canaid::Helpers::PermissionsHelper
include ReportsHelper
MY_MODULE_ADDONS_ELEMENTS = []
@ -13,8 +14,9 @@ module ReportActions
@element_position = 0
@report = report
@template_values = template_values
@repositories = Repository.accessible_by_teams(report.project.team)
.where(id: @content['repositories']).active
@repositories = report.project
.assigned_repositories_and_snapshots
.select { |repository| @content['repositories'].include?(repository.id) }
end
def save_with_content
@ -57,47 +59,48 @@ module ReportActions
private
def generate_content
@content['experiments'].each do |exp_id|
generate_experiment_content(exp_id, @content['tasks'][exp_id])
save_element!({ 'project_id' => @report.project_id }, :project_header, nil)
@content['experiments'].each do |experiment|
generate_experiment_content(experiment[:id], experiment[:my_module_ids])
end
end
def generate_experiment_content(exp_id, my_modules)
experiment = Experiment.find_by(id: exp_id)
def generate_experiment_content(experiment_id, my_module_ids)
experiment = Experiment.find_by(id: experiment_id)
return if !experiment && !can_read_experiment?(experiment, @user)
experiment_element = save_element!({ 'experiment_id' => experiment.id }, :experiment, nil)
generate_my_modules_content(experiment, experiment_element, my_modules)
generate_my_modules_content(experiment, experiment_element, my_module_ids)
end
def generate_my_modules_content(experiment, experiment_element, selected_my_modules)
def generate_my_modules_content(experiment, experiment_element, my_module_ids)
my_modules = experiment.my_modules
.active
.where(id: selected_my_modules)
my_modules.sort_by { |m| selected_my_modules.index m.id }.each do |my_module|
.where(id: my_module_ids)
my_modules.sort_by { |m| my_module_ids.index m.id }.each do |my_module|
my_module_element = save_element!({ 'my_module_id' => my_module.id }, :my_module, experiment_element)
@repositories.each do |repository|
repository = assigned_repository_or_snapshot(my_module, repository)
next unless repository
save_element!(
{ 'my_module_id' => my_module.id, 'repository_id' => repository.id },
:my_module_repository,
my_module_element
)
end
MY_MODULE_ADDONS_ELEMENTS.each do |e|
public_send("generate_#{e}_content", my_module, my_module_element)
end
end
end
def save_element!(reference, type_of, parent)
def save_element!(references, type_of, parent)
el = ReportElement.new
el.position = @element_position
el.report = @report
el.parent = parent
el.type_of = type_of
el.set_element_references(reference)
el.assign_attributes(references)
el.save!
@element_position += 1

View file

@ -11,7 +11,10 @@ module ReportActions
end
def save
ActiveRecord::Base.transaction do
# we lock the row, to prevent two repository cells being created at the same location
# as the RepositoryCell validation would pass in both concurrent transactions
@repository_row.with_lock do
asset = create_new_asset
delete_old_repository_cell
@new_cell_value = create_new_cell_value(asset)

View file

@ -4,7 +4,10 @@ module Reports::Docx::DrawMyModuleRepository
def draw_my_module_repository(subject)
my_module = subject.my_module
repository = subject.repository
return unless can_read_experiment?(@user, my_module.experiment) && can_read_repository?(@user, repository)
repository = assigned_repository_or_snapshot(my_module, repository)
return unless repository && can_read_experiment?(@user, my_module.experiment) &&
(repository.is_a?(RepositorySnapshot) || can_read_repository?(@user, repository))
repository_data = my_module.repository_docx_json(repository)

View file

@ -50,6 +50,8 @@ module Reports
elements = []
temp_p = []
raw_elements.each do |elem|
next unless elem
if %w(image newline table ol ul).include? elem[:type]
unless temp_p.empty?
elements.push(type: 'p', children: temp_p)

View file

@ -83,9 +83,13 @@ class RepositoryDatatableService
results = repository_rows.where(id: repository_row_matches)
results = results.or(repository_rows.where(id: matched_by_user))
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |field, include_hash|
custom_cell_matches = repository_rows.joins(repository_cells: include_hash)
.where_attributes_like(field, search_value)
data_types = @repository.repository_columns.pluck(:data_type).uniq
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |data_type, config|
next unless data_types.include?(data_type.to_s)
custom_cell_matches = repository_rows.joins(repository_cells: config[:includes])
.where_attributes_like(config[:field], search_value)
results = results.or(repository_rows.where(id: custom_cell_matches))
end

View file

@ -36,9 +36,13 @@ class RepositorySnapshotDatatableService < RepositoryDatatableService
results = repository_rows.where(id: repository_row_matches)
results = results.or(repository_rows.where(id: matched_by_user))
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |field, include_hash|
custom_cell_matches = repository_rows.joins(repository_cells: include_hash)
.where_attributes_like(field, search_value)
data_types = @repository.repository_columns.pluck(:data_type).uniq
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |data_type, config|
next unless data_types.include?(data_type.to_s)
custom_cell_matches = repository_rows.joins(repository_cells: config[:includes])
.where_attributes_like(config[:field], search_value)
results = results.or(repository_rows.where(id: custom_cell_matches))
end

View file

@ -4,7 +4,7 @@
<%= link_to protocols_path, {class: "new-protocol btn btn-secondary"} do %>
<i class="fas fa-edit"></i><%= t("dashboard.quick_start.new_protocol") %>
<% end %>
<%= link_to reports_path, {class: "new-report btn btn-secondary"} do %>
<%= link_to new_report_path, {class: "new-report btn btn-secondary"} do %>
<i class="fas fa-clipboard-check"></i><%= t("dashboard.quick_start.new_report") %>
<% end %>
</div>

View file

@ -11,6 +11,8 @@
<div class="file-preview-container">
<% if report_type == 'pdf' %>
<%= render partial: 'shared/pdf_viewer.html.erb', locals: { asset: report.pdf_file, report_document: true } %>
<% elsif report_type == 'docx' %>
<%= render partial: 'shared/pdf_viewer.html.erb', locals: { asset: report.docx_preview_file, report_document: true } %>
<% else %>
<div>
<i class="fas fa-10x fa-file-word"></i>

View file

@ -1,18 +0,0 @@
<% if !defined? show_sort then show_sort = false end %>
<% if !defined? show_move_up then show_move_up = true end %>
<% if !defined? show_move_down then show_move_down = true end %>
<% if !defined? show_remove then show_remove = true end %>
<%if show_sort %>
<a href="" data-action="sort-asc" title="<%=t "projects.reports.elements.all.sort_asc" %>"><span class="fas fa-sort-by-attributes"></span></a>
<a href="" data-action="sort-desc" title="<%=t "projects.reports.elements.all.sort_desc" %>"><span class="fas fa-sort-by-attributes-alt"></span></a>
<% end %>
<% if show_move_up %>
<a href="" data-action="move-up" title="<%=t "projects.reports.elements.all.move_up" %>"><span class="fas fa-chevron-up"></span></a>
<% end %>
<% if show_move_down %>
<a href="" data-action="move-down" title="<%=t "projects.reports.elements.all.move_down" %>"><span class="fas fa-chevron-down"></span></a>
<% end %>
<% if show_remove %>
<a href="" data-action="remove" title="<%=t "projects.reports.elements.all.remove" %>"><span class="fas fa-times"></span></a>
<% end %>

View file

@ -1,22 +1,13 @@
<% experiment ||= report_element.experiment %>
<% timestamp = experiment.created_at %>
<% name = experiment.name %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-experiment-element"
data-ts="<%= timestamp.to_i %>"
data-type="experiment"
data-id='{ "experiment_id": <%= experiment.id %> }'
data-scroll-id="<%= experiment.id %>"
data-modal-title="<%=t "projects.reports.elements.modals.experiment_contents.head_title",
experiment: experiment.name %>" data-name="<%= name %>" data-icon-class="fas fa-flask">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-experiment-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left user-time">
<%=t "projects.reports.elements.experiment.user_time", timestamp: l(timestamp, format: :full) %>
<%= t('projects.reports.elements.experiment.user_time', timestamp: l(timestamp, format: :full)) %>
<b><%= link_to t('projects.reports.elements.all.scinote_link'),canvas_experiment_url(experiment), target: :_blank %></b>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
</div>
</div>
</div>
<div class="report-element-body" data-hook="report-experiment-element">
@ -24,9 +15,9 @@
<div class="pull-left experiment-name">
<h4>
<i class="fas fa-flask"></i>
<%= name %>
<%= experiment.name %>
<% if experiment.archived? %>
<span class="label label-warning"><%=t 'search.index.archived' %></span>
<span class="label label-warning"><%= t('search.index.archived') %></span>
<% end %>
</h4>
</div>
@ -34,9 +25,9 @@
<div class="row">
<div class="col-xs-12">
<% if experiment.description.present? %>
<%= custom_auto_link(experiment.description, team: current_team, base64_encoded_imgs: for_export_all) %>
<%= custom_auto_link(experiment.description, team: current_team, base64_encoded_imgs: export_all) %>
<% else %>
<em><%=t "projects.reports.elements.experiment.no_description" %></em>
<em><%= t('projects.reports.elements.experiment.no_description') %></em>
<% end %>
</div>
</div>

View file

@ -1,45 +1,39 @@
<% my_module ||= @my_module %>
<% timestamp = Time.current + 1.year - 2.days %>
<% my_module ||= report_element.my_module %>
<% activities = ActivitiesService.my_module_activities(my_module).order(created_at: :desc) %>
<div class="report-element report-module-activity-element" data-ts="<%= timestamp.to_i %>" data-type="my_module_activity" data-id='{ "my_module_id": <%= my_module.id %> }' data-scroll-id="<%= my_module.id %>" data-name="<%=t "projects.reports.elements.module_activity.sidebar_name" %>" data-icon-class="fas fa-list">
<div class="report-element report-module-activity-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left activity-icon">
<span class="fas fa-list"></span>
</div>
<div class="pull-left activity-name">
<%=t "projects.reports.elements.module_activity.name", my_module: my_module.name %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
<%= t('projects.reports.elements.module_activity.name', my_module: my_module.name) %>
</div>
</div>
</div>
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 activity-container">
<% if activities.any? %>
<!-- TODO: This might become potentially very big! -->
<% if activities.present? %>
<ul class="no-style activity-list">
<% activities.each do |activity| %>
<% activity_ts = activity.created_at %>
<li class="activity" data-ts="<%= activity_ts.to_i %>">
<li class="activity">
<span class="activity-prefix">
<%=l activity_ts, format: :full %>
<%= l(activity.created_at, format: :full) %>
</span>
<span class="activity-message">
&nbsp;
<% if activity.old_activity? %>
<%= sanitize_input(activity.message) %>
<%= activity.message %>
<% else %>
<%= sanitize_input(generate_activity_content(activity, no_links: true)) %>
<%= generate_activity_content(activity, no_links: true) %>
<% end %>
</span>
</li>
<% end %>
</ul>
<% else %>
<em><%=t "projects.reports.elements.module_activity.no_activity" %></em>
<em><%= t('projects.reports.elements.module_activity.no_activity') %></em>
<% end %>
</div>
</div>

View file

@ -1,17 +1,13 @@
<% if my_module.blank? and @my_module.present? then my_module = @my_module end %>
<% my_module ||= report_element.my_module %>
<% timestamp = my_module.created_at %>
<% name = my_module.name %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-module-element" data-ts="<%= timestamp.to_i %>" data-type="my_module" data-id='{ "my_module_id": <%= my_module.id %> }' data-scroll-id="<%= my_module.id %>" data-modal-title="<%=t "projects.reports.elements.modals.module_contents.head_title", module: my_module.name %>" data-name="<%= name %>" data-icon-class="fas fa-credit-card">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-module-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left user-time">
<%= t("projects.reports.elements.module.user_time", timestamp: l(timestamp, format: :full)) %>
<%= t('projects.reports.elements.module.user_time', timestamp: l(timestamp, format: :full)) %>
<b><%= link_to t('projects.reports.elements.all.scinote_link'), protocols_my_module_url(my_module), target: :_blank %></b>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
</div>
</div>
</div>
<div class="report-element-body">
@ -19,9 +15,9 @@
<div class="pull-left module-name">
<h4>
<span class="fas fa-credit-card"></span>
<%= name %>
<%= my_module.name %>
<% if my_module.archived? %>
<span class="label label-warning"><%=t 'search.index.archived' %></span>
<span class="label label-warning"><%= t('search.index.archived') %></span>
<% end %>
</h4>
</div>
@ -30,32 +26,34 @@
<% if my_module.started_on.present? %>
<%= t('projects.reports.elements.module.started_on', started_on: l(my_module.started_on, format: :full)) %>
<% else %>
<em><%= t("projects.reports.elements.module.no_start_date") %></em>
<em><%= t('projects.reports.elements.module.no_start_date') %></em>
<% end %>
</p>
<p class="module-due-date">
<% if my_module.due_date.present? %>
<%= t("projects.reports.elements.module.due_date", due_date: l(my_module.due_date, format: :full)) %>
<%= t('projects.reports.elements.module.due_date', due_date: l(my_module.due_date, format: :full)) %>
<% else %>
<em><%= t("projects.reports.elements.module.no_due_date") %></em>
<em><%= t('projects.reports.elements.module.no_due_date') %></em>
<% end %>
</p>
<p class="module-status">
<% status = my_module.my_module_status %>
<%= t("projects.reports.elements.module.status") %>
<span class="status-block" style="background: <%= status.color %>"><%= status.name %></span>
<%= t('projects.reports.elements.module.status') %>
<span class="status-block" style="background: <%= status.color %>">
<%= status.name %>
</span>
<% if my_module.completed? %>
<span style="margin-left: 10px;">
<%= t("my_modules.states.completed") %>
<%= t('my_modules.states.completed') %>
<%= l(my_module.completed_on, format: :full) %>
</span>
<% end %>
</p>
<div class="row module-tags">
<div class="pull-left">
<%= t("projects.reports.elements.module.tags_header") %>
<%= t('projects.reports.elements.module.tags_header') %>
</div>
<% if my_module.tags.any? %>
<% if my_module.tags.present? %>
<% my_module.tags.each do |tag| %>
<div class="pull-left module-tag" style="background-color: <%= tag.color %>;">
<%= tag.name %>
@ -63,19 +61,19 @@
<% end %>
<% else %>
<div class="pull-left module-no-tag">
<em><%= t("projects.reports.elements.module.no_tags") %></em>
<em><%= t('projects.reports.elements.module.no_tags') %></em>
</div>
<% end %>
</div>
<div class="row">
<div class="col-xs-12">
<% if my_module.description.present? %>
<%= custom_auto_link(my_module.prepare_for_report(:description, for_export_all),
<%= custom_auto_link(my_module.prepare_for_report(:description, export_all),
team: current_team,
simple_format: false,
base64_encoded_imgs: for_export_all) %>
base64_encoded_imgs: export_all) %>
<% else %>
<em><%= t("projects.reports.elements.module.no_description") %></em>
<em><%= t('projects.reports.elements.module.no_description') %></em>
<% end %>
</div>
</div>
@ -86,16 +84,16 @@
<% end %>
<% filter_steps_for_report(my_module.protocol.steps, @settings).order(:position).each do |step| %>
<%= render partial: 'reports/elements/my_module_step_element.html.erb', locals: { step: step } %>
<%= render partial: 'reports/elements/my_module_step_element.html.erb', locals: { step: step, export_all: export_all } %>
<% end %>
<% order_results_for_report(my_module.results, @settings.dig('task', 'result_order')).each do |result| %>
<% if result.is_asset && @settings.dig('task', 'file_results') %>
<%= render partial: 'reports/elements/my_module_result_asset_element.html.erb', locals: { result: result, report: report } %>
<%= render partial: 'reports/elements/my_module_result_asset_element.html.erb', locals: { result: result, report: report, export_all: export_all } %>
<% elsif result.is_table && @settings.dig('task', 'table_results') %>
<%= render partial: 'reports/elements/my_module_result_table_element.html.erb', locals: { result: result } %>
<%= render partial: 'reports/elements/my_module_result_table_element.html.erb', locals: { result: result, export_all: export_all } %>
<% elsif result.is_text && @settings.dig('task', 'text_results') %>
<%= render partial: 'reports/elements/my_module_result_text_element.html.erb', locals: { result: result } %>
<%= render partial: 'reports/elements/my_module_result_text_element.html.erb', locals: { result: result, export_all: export_all } %>
<% end %>
<% end %>
</div>
@ -108,7 +106,7 @@
<% if @settings.dig('task', 'activities') %>
<div class="report-element-children">
<%= render partial: 'reports/elements/my_module_activity_element.html.erb', locals: { my_module: my_module } %>
<%= render partial: 'reports/elements/my_module_activity_element.html.erb', locals: { my_module: my_module, export_all: export_all } %>
</div>
<% end %>
</div>

View file

@ -1,24 +1,20 @@
<% protocol ||= my_module.protocol %>
<% my_module = protocol.my_module %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-module-protocol-element" data-ts="<%= protocol.created_at %>" data-type="my_module_protocol" data-id='{ "my_module_id": <%= my_module.id %> }' data-scroll-id="<%= protocol.id %>">
<% protocol ||= report_element.my_module.protocol %>
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-module-protocol-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left user-time">
<%=t "projects.reports.elements.module.protocol.user_time", timestamp: l(protocol.created_at, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
<%= t('projects.reports.elements.module.protocol.user_time', timestamp: l(protocol.created_at, format: :full)) %>
</div>
</div>
</div>
<div class="report-element-body">
<div class="row module-protocol-description">
<% if protocol.description.present? %>
<%= custom_auto_link(protocol.prepare_for_report(:description, for_export_all),
<%= custom_auto_link(protocol.prepare_for_report(:description, export_all),
team: current_team,
simple_format: false,
base64_encoded_imgs: for_export_all) %>
base64_encoded_imgs: export_all) %>
<% else %>
<em><%= t('my_modules.protocols.protocol_status_bar.no_description') %></em>
<% end %>

View file

@ -1,55 +1,45 @@
<% my_module ||= @my_module %>
<% repository ||= nil %>
<% element_id ||= repository&.id %>
<% repository_snapshot ||= nil %>
<% repository = assigned_repository_or_snapshot(my_module, element_id, repository, repository_snapshot) %>
<% timestamp = Time.current + 1.year - 1.days %>
<% rows_json = my_module.repository_json_hot(repository, :desc) %>
<div class="report-element report-module-repository-element"
data-sort-hot="1"
data-ts="<%= timestamp.to_i %>"
data-type="my_module_repository"
data-id='{ "my_module_id": <%= my_module.id %>, "repository_id": <%= repository.id %> }'
data-scroll-id="<%= "#{my_module.id}_#{repository.id}" %>"
data-name="<%= repository.name %>"
data-icon-class="fas fa-list-alt">
<div class="report-element-header">
<div class="row">
<div class="pull-left repository-icon">
<i class="fas fa-list-alt"></i>
</div>
<div class="pull-left repository-name">
<%= t('projects.reports.elements.module_repository.name', repository: repository.name, my_module: my_module.name) %>
<i><%= t('projects.reports.index.deleted') if repository.is_a?(RepositorySnapshot) && !repository.original_repository %></i>
</div>
<% if defined?(export_all) && export_all %>
<div class="pull-left table-name">
<a href="<%= path[:file] %>">
<em><%= t('projects.reports.elements.module_repository.table_name', name: filename) %></em>
</a>
<% my_module ||= report_element.my_module %>
<% repository ||= report_element.repository %>
<% repository = assigned_repository_or_snapshot(my_module, repository) %>
<% if repository %>
<% rows_json = my_module.repository_json_hot(repository, :desc) %>
<div class="report-element report-module-repository-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left repository-icon">
<i class="fas fa-list-alt"></i>
</div>
<% end %>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
<div class="pull-left repository-name">
<%= t('projects.reports.elements.module_repository.name', repository: repository.name, my_module: my_module.name) %>
<i><%= t('projects.reports.index.deleted') if repository.is_a?(RepositorySnapshot) && !repository.original_repository %></i>
</div>
<% if defined?(export_all) && export_all %>
<div class="pull-left table-name">
<% file_link = @obj_filenames.dig(:repositories, repository.id, :file) %>
<a href="<%= file_link %>">
<em><%= t('projects.reports.elements.module_repository.table_name', name: file_link&.split('/')&.last) %></em>
</a>
</div>
<% end %>
</div>
</div>
</div>
<div class="report-element-body">
<% if rows_json[:data].count > 0 %>
<input type="hidden" class="hot-table-contents hot-repository-items" value='<%= rows_json.to_json.force_encoding(Encoding::UTF_8) %>' />
<div class="hot-table-container"></div>
<table class="report-common-table-format"></table>
<% else %>
<div class="row">
<div class="col-xs-12">
<em><%= t('projects.reports.elements.module_repository.no_items') %></em>
<div class="report-element-body">
<% if rows_json[:data].count > 0 %>
<input type="hidden" class="hot-table-contents hot-repository-items" value='<%= rows_json.to_json.force_encoding(Encoding::UTF_8) %>' />
<div class="hot-table-container"></div>
<table class="report-common-table-format"></table>
<% else %>
<div class="row">
<div class="col-xs-12">
<em><%= t('projects.reports.elements.module_repository.no_items') %></em>
</div>
</div>
<% end %>
</div>
<% if defined?(children) %>
<div class="report-element-children">
<%= children %>
</div>
<% end %>
</div>
<% if defined?(children) %>
<div class="report-element-children">
<%= children %>
</div>
<% end %>
</div>
<% end %>

View file

@ -1,16 +1,7 @@
<% result ||= @result %>
<% result ||= report_element.result %>
<% asset = result.asset %>
<% comments = result.result_comments %>
<% timestamp = asset.created_at %>
<% icon_class = 'fas ' + file_fa_icon_class(asset) if asset.file_name %>
<div class="report-element report-result-element report-result-asset-element"
data-ts="<%= timestamp.to_i %>"
data-type="result_asset"
data-id='{ "result_id": <%= result.id %> }'
data-scroll-id="<%= result.id %>"
data-modal-title="<%= t("projects.reports.elements.modals.result_contents.head_title", result: result.name) %>"
data-name="<%= result.name %>"
data-icon-class="<%= icon_class %>">
<div class="report-element report-result-element report-result-asset-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left result-icon">
@ -24,8 +15,9 @@
</div>
<div class="pull-left file-name">
<% if defined? export_all and export_all %>
<a href="<%= path[:file] %>">
<em><%= t("projects.reports.elements.result_asset.file_name", file: filename) %></em>
<% file_link = @obj_filenames.dig(:assets, asset.id, :file) %>
<a href="<%= file_link %>">
<em><%= t("projects.reports.elements.result_asset.file_name", file: file_link&.split('/')&.last) %></em>
</a>
<% else %>
<em>
@ -41,9 +33,6 @@
<%= t('projects.reports.elements.result_asset.full_preview_attached') %>
<% end %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb" %>
</div>
</div>
</div>
<div class="row"></div>
@ -52,7 +41,7 @@
<div class="row">
<div class="col-xs-12 file-image">
<% if defined?(export_all) && export_all %>
<img class="report-export-img" src="<%= path[:preview] %>">
<img class="report-export-img" src="<%= @obj_filenames.dig(:assets, asset.id, :preview) %>">
<% else %>
<%= report_image_asset_url(asset) %>
<% end %>

View file

@ -1,8 +1,7 @@
<% result ||= @result %>
<% result ||= report_element.result %>
<% table = result.table %>
<% comments = result.result_comments %>
<% timestamp = table.created_at %>
<div class="report-element report-result-element report-result-table-element" data-ts="<%= timestamp.to_i %>" data-type="result_table" data-id='{ "result_id": <%= result.id %> }' data-scroll-id="<%= result.id %>" data-modal-title="<%=t "projects.reports.elements.modals.result_contents.head_title", result: result.name %>" data-name="<%= result.name %>" data-icon-class="fas fa-table">
<div class="report-element report-result-element report-result-table-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left result-name-container">
@ -12,23 +11,19 @@
<div class="pull-left result-name">
<%= result.name %>
<% if result.archived? %>
<span class="label label-warning"><%=t 'search.index.archived' %></span>
<span class="label label-warning"><%= t('search.index.archived') %></span>
<% end %>
</div>
<% if defined? export_all and export_all %>
<div class="pull-left table-name">
<a href="<%= path[:file] %>">
<em><%=t "projects.reports.elements.result_table.table_name",
name: filename %></em>
</a>
<% file_link = @obj_filenames.dig(:tables, table.id, :file) %>
<a href="<%= file_link %>">
<em><%=t "projects.reports.elements.result_table.table_name", name: file_link&.split('/')&.last %></em>
</a>
</div>
<% end %>
<div class="pull-left user-time">
<%=t "projects.reports.elements.result_table.user_time", user: result.user.full_name , timestamp: l(timestamp, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb" %>
<%= t('projects.reports.elements.result_table.user_time', user: result.user.full_name , timestamp: l(timestamp, format: :full)) %>
</div>
</div>
</div>

View file

@ -1,10 +1,9 @@
<% if result.blank? and @result.present? then result = @result end %>
<% result ||= report_element.result %>
<% result_text = result.result_text %>
<% comments = result.result_comments %>
<% timestamp = result.created_at %>
<% name = result.name %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-result-element report-result-text-element" data-ts="<%= timestamp.to_i %>" data-type="result_text" data-id='{ "result_id": <%= result.id %> }' data-scroll-id="<%= result.id %>" data-modal-title="<%=t "projects.reports.elements.modals.result_contents.head_title", result: result.name %>" data-name="<%= name %>" data-icon-class="fas fa-asterisk">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-result-element report-result-text-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left result-icon">
@ -13,25 +12,22 @@
<div class="pull-left result-name">
<%= name %>
<% if result.archived? %>
<span class="label label-warning"><%=t 'search.index.archived' %></span>
<span class="label label-warning"><%= t('search.index.archived') %></span>
<% end %>
</div>
<div class="pull-left user-time">
<%=t "projects.reports.elements.result_text.user_time", user: result.user.full_name, timestamp: l(timestamp, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb" %>
<%= t('projects.reports.elements.result_text.user_time', user: result.user.full_name, timestamp: l(timestamp, format: :full)) %>
</div>
</div>
</div>
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 text-container ql-editor">
<%= custom_auto_link(result_text.prepare_for_report(:text, for_export_all),
<%= custom_auto_link(result_text.prepare_for_report(:text, export_all),
team: current_team,
simple_format: false,
tags: %w(img),
base64_encoded_imgs: for_export_all) %>
base64_encoded_imgs: export_all) %>
</div>
</div>
</div>

View file

@ -1,26 +1,16 @@
<% step ||= @step %>
<% step ||= report_element.step %>
<% step_type_str = step.completed ? 'completed' : 'uncompleted' %>
<% user = step.completed? ? step.last_modified_by : step.user %>
<% timestamp = step.completed ? step.completed_on : step.created_at %>
<% tables = step.tables %>
<% assets = step.assets %>
<% checklists = step.checklists %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-step-element"
data-ts="<%= timestamp.to_i %>"
data-type="step"
data-id='{ "step_id": <%= step.id %> }'
data-scroll-id="<%= step.id %>"
data-modal-title="<%=t "projects.reports.elements.modals.step_contents.head_title", step: step.name %>"
data-name="<%=t "projects.reports.elements.step.sidebar_name", pos: (step.position_plus_one), name: step.name %>"
data-icon-class="fas fa-arrow-circle-right">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-step-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left user-time">
<%=t "projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
<%= t("projects.reports.elements.step.#{step_type_str}.user_time", user: user.full_name , timestamp: l(timestamp, format: :full)) %>
</div>
</div>
</div>
@ -29,7 +19,7 @@
<div class="pull-left step-name">
<h5>
<span class="fas fa-arrow-circle-right"></span>
<b><%=t "projects.reports.elements.step.step_pos", pos: (step.position_plus_one) %></b>&nbsp;<%= step.name %>
<b><%= t('projects.reports.elements.step.step_pos', pos: (step.position_plus_one)) %></b>&nbsp;<%= step.name %>
<%= step_status_label(step) %>
</h5>
</div>
@ -37,13 +27,13 @@
<div class="row">
<div class="col-xs-12 ql-editor">
<% if step.description.present? %>
<%= custom_auto_link(step.prepare_for_report(:description, for_export_all),
<%= custom_auto_link(step.prepare_for_report(:description, export_all),
team: current_team,
simple_format: false,
tags: %w(img),
base64_encoded_imgs: for_export_all) %>
base64_encoded_imgs: export_all) %>
<% else %>
<em><%=t "projects.reports.elements.step.no_description" %></em>
<em><%= t('projects.reports.elements.step.no_description') %></em>
<% end %>
</div>
</div>
@ -51,21 +41,21 @@
<div class="report-element-children">
<% if @settings.dig('task', 'protocol', 'step_tables') %>
<% tables.each do |table| %>
<%= render partial: 'reports/elements/step_table_element.html.erb', locals: { table: table } %>
<%= render partial: 'reports/elements/step_table_element.html.erb', locals: { table: table, export_all: export_all } %>
<% end %>
<% end %>
<% if @settings.dig('task', 'protocol', 'step_files') %>
<% assets.each do |asset| %>
<%= render partial: 'reports/elements/step_asset_element.html.erb', locals: { asset: asset } %>
<%= render partial: 'reports/elements/step_asset_element.html.erb', locals: { asset: asset, export_all: export_all } %>
<% end %>
<% end %>
<% if @settings.dig('task', 'protocol', 'step_checklists') %>
<% checklists.each do |checklist| %>
<%= render partial: 'reports/elements/step_checklist_element.html.erb', locals: { checklist: checklist } %>
<%= render partial: 'reports/elements/step_checklist_element.html.erb', locals: { checklist: checklist, export_all: export_all } %>
<% end %>
<% end %>
<% if @settings.dig('task', 'protocol', 'step_comments') %>
<%= render partial: 'reports/elements/step_comments_element.html.erb', locals: { step: step } %>
<%= render partial: 'reports/elements/step_comments_element.html.erb', locals: { step: step, export_all: export_all } %>
<% end %>
</div>
<% if defined?(children) %>

View file

@ -1,20 +0,0 @@
<% if !defined? hide then hide = false end %>
<% if !defined? initial then initial = false end %>
<div class="new-element <%= "hidden" if hide %> <%= "initial" if initial %>" data-ts="ignore" data-type="new" title="<%=t "projects.reports.elements.new_element.title" %>">
<a href="" class="new-element-href" data-action="add-new-elements">
<div class="line left-line">
<div class="filler-wrapper">
<div class="filler"></div>
</div>
</div>
<div class="plus-icon">
<span class="fas fa-plus"></span>
</div>
<div class="line right-line">
<div class="filler-wrapper">
<div class="filler"></div>
</div>
</div>
<div class="clear"></div>
</a>
</div>

View file

@ -1,10 +1,9 @@
<% if project.blank? and @project.present? then project = @project end %>
<% name = t("projects.reports.elements.project_header.title", project: project.name) %>
<div class="report-element report-project-header-element" data-ts="ignore" data-type="project_header" data-id='{ "project_id": <%= project.id %> }' data-scroll-id="<%= project.id %>" data-name="<%= name %>" data-icon-class="fas fa-heading">
<% project ||= report_element.project %>
<div class="report-element report-project-header-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left user-time">
<%=t "projects.reports.elements.project_header.user_time", timestamp: l(project.created_at, format: :full) %>
<%= t('projects.reports.elements.project_header.user_time', timestamp: l(project.created_at, format: :full)) %>
</div>
</div>
</div>
@ -12,9 +11,9 @@
<div class="row">
<div class="col-xs-12 project-name">
<h2>
<%= name %>
<%= t('projects.reports.elements.project_header.title', project: project.name) %>
<% if project.archived? %>
<span class="label label-warning"><%=t 'search.index.archived' %></span>
<span class="label label-warning"><%= t('search.index.archived') %></span>
<% end %>
</h2>
</div>

View file

@ -1,33 +1,29 @@
<% result ||= @result %>
<% result ||= report_element.result %>
<% comments = result.result_comments.order(created_at: :desc) %>
<% timestamp = Time.current + 1.year %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-comments-element report-result-comments-element" data-ts="<%= timestamp.to_i %>" data-type="result_comments" data-id='{ "result_id": <%= result.id %> }' data-scroll-id="<%= result.id %>" data-name="<%=t "projects.reports.elements.result_comments.sidebar_name" %>" data-icon-class="fas fa-comment">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-comments-element report-result-comments-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left comments-icon">
<span class="fas fa-comment"></span>
</div>
<div class="pull-left comments-name">
<%=t "projects.reports.elements.result_comments.name", result: result.name %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true, show_move_up: false, show_move_down: false } %>
<%= t('projects.reports.elements.result_comments.name', result: result.name) %>
</div>
</div>
</div>
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 comments-container simple">
<% if comments.any? %>
<% if comments.present? %>
<ul class="no-style content-comments">
<% comments.each do |comment| %>
<%= render partial: 'shared/comments/item.html.erb',
locals: { comment: comment, readonly: true, report: true, export_all: for_export_all } %>
locals: { comment: comment, readonly: true, report: true, export_all: export_all } %>
<% end %>
</ul>
<% else %>
<em><%=t "projects.reports.elements.result_comments.no_comments" %></em>
<em><%= t('projects.reports.elements.result_comments.no_comments') %></em>
<% end %>
</div>
</div>

View file

@ -1,7 +1,6 @@
<% asset ||= @asset %>
<% asset ||= report_element.asset %>
<% timestamp = asset.created_at %>
<% icon_class = file_fa_icon_class(asset) if asset.file_name %>
<div class="report-element report-step-attachment-element report-step-asset-element" data-ts="<%= timestamp.to_i %>" data-type="step_asset" data-id='{ "asset_id": <%= asset.id %> }' data-scroll-id="<%= asset.id %>" data-name="<%=t "projects.reports.elements.step_asset.sidebar_name", file: asset.file_name %>" data-icon-class="<%= icon_class %>">
<div class="report-element report-step-attachment-element report-step-asset-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left attachment-icon <%= defined?(export_all) && export_all ? 'export-all-icons' : '' %>">
@ -9,8 +8,9 @@
</div>
<div class="pull-left file-name">
<% if defined? export_all and export_all %>
<a href="<%= path[:file] %>">
<em><%= t('projects.reports.elements.step_asset.file_name', file: filename) %></em>
<% file_link = @obj_filenames.dig(:assets, asset.id, :file) %>
<a href="<%= file_link %>">
<em><%= t('projects.reports.elements.step_asset.file_name', file: file_link&.split('/')&.last) %></em>
</a>
<% else %>
<em>
@ -18,14 +18,10 @@
file: truncate(asset.file_name, length: Constants::FILENAME_TRUNCATION_LENGTH)) %>
<%= link_to t('projects.reports.elements.download'), asset_download_url(asset, disposition: 'attachment'), class: 'download-link', target: :_blank %>
</em>
<% end %>
</div>
<div class="pull-left user-time">
<%=t 'projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: 'reports/elements/element_controls.html.erb' %>
<%= t('projects.reports.elements.step_asset.user_time', timestamp: l(timestamp, format: :full)) %>
</div>
</div>
</div>
@ -34,7 +30,7 @@
<div class="row">
<div class="col-xs-12 file-image">
<% if defined?(export_all) && export_all %>
<img class="report-export-img" src="<%= path[:preview] %>">
<img class="report-export-img" src="<%= @obj_filenames.dig(:assets, asset.id, :preview) %>">
<% else %>
<%= report_image_asset_url(asset) %>
<% end %>

View file

@ -1,24 +1,21 @@
<% if checklist.blank? and @checklist.present? then checklist = @checklist end %>
<% checklist ||= report_element.checklist %>
<% items = checklist.checklist_items %>
<% timestamp = checklist.created_at %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-step-attachment-element report-step-checklist-element" data-ts="<%= timestamp.to_i %>" data-type="step_checklist" data-id='{ "checklist_id": <%= checklist.id %> }' data-scroll-id="<%= checklist.id %>" data-name="<%= checklist.name %>" data-icon-class="fas fa-tasks">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-step-attachment-element report-step-checklist-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left attachment-icon">
<span class="fas fa-tasks"></span>
<span class="fas fa-tasks"></span>
</div>
<div class="pull-left checklist-name">
<%= custom_auto_link(t('projects.reports.elements.step_checklist.checklist_name',
name: checklist.name),
team: current_team,
base64_encoded_imgs: for_export_all) %>
name: checklist.name),
team: current_team,
base64_encoded_imgs: export_all) %>
</div>
<div class="pull-left user-time">
<%=t 'projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: 'reports/elements/element_controls.html.erb' %>
<%= t('projects.reports.elements.step_checklist.user_time', timestamp: l(timestamp, format: :full)) %>
</div>
</div>
</div>
@ -32,7 +29,7 @@
team: current_team,
simple_format: true,
wrapper_tag: { wrapper_tag: 'span'},
base64_encoded_imgs: for_export_all) %>
base64_encoded_imgs: export_all) %>
</span>
</li>
<% end %>

View file

@ -1,33 +1,29 @@
<% if step.blank? and @step.present? then step = @step end %>
<% step ||= report_element.step %>
<% comments = step.step_comments.order(created_at: :desc) %>
<% timestamp = Time.current + 1.year %>
<% for_export_all = defined?(export_all) && export_all %>
<div class="report-element report-comments-element report-step-comments-element" data-ts="<%= timestamp.to_i %>" data-order="asc" data-type="step_comments" data-id='{ "step_id": <%= step.id %> }' data-scroll-id="<%= step.id %>" data-name="<%=t "projects.reports.elements.step_comments.sidebar_name" %>" data-icon-class="fas fa-comment">
<% export_all = defined?(export_all) && export_all %>
<div class="report-element report-comments-element report-step-comments-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left comments-icon">
<span class="fas fa-comment"></span>
</div>
<div class="pull-left comments-name">
<%=t "projects.reports.elements.step_comments.name", step: step.name %>
</div>
<div class="pull-right controls">
<%= render partial: "reports/elements/element_controls.html.erb", locals: { show_sort: true } %>
<%= t('projects.reports.elements.step_comments.name', step: step.name) %>
</div>
</div>
</div>
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 comments-container simple">
<% if comments.any? %>
<% if comments.present? %>
<ul class="no-style content-comments">
<% comments.each do |comment| %>
<%= render partial: 'shared/comments/item.html.erb',
locals: { comment: comment, readonly: true, report: true, export_all: for_export_all } %>
locals: { comment: comment, readonly: true, report: true, export_all: export_all } %>
<% end %>
</ul>
<% else %>
<em><%=t "projects.reports.elements.step_comments.no_comments" %></em>
<em><%= t('projects.reports.elements.step_comments.no_comments') %></em>
<% end %>
</div>
</div>

View file

@ -1,30 +1,29 @@
<% table ||= @table %>
<% table ||= report_element.table %>
<% timestamp = table.created_at %>
<div class="report-element report-step-attachment-element report-step-table-element" data-ts="<%= timestamp.to_i %>" data-type="step_table" data-id='{ "table_id": <%= table.id %> }' data-scroll-id="<%= table.id %>" data-name="<%= table.name %>" data-icon-class="fas fa-table">
<div class="report-element report-step-attachment-element report-step-table-element">
<div class="report-element-header">
<div class="row">
<div class="pull-left attachment-icon">
<span class="fas fa-table"></span>
<span class="fas fa-table"></span>
</div>
<div class="pull-left table-name">
<% if defined? export_all and export_all %>
<a href="<%= path[:file] %>">
<em><%=t 'projects.reports.elements.step_table.table_name',
name: filename %></em>
<% file_link = @obj_filenames.dig(:tables, table.id, :file) %>
<a href="<%= file_link %>">
<em>
<%= t('projects.reports.elements.step_table.table_name', name: file_link&.split('/')&.last) %>
</em>
</a>
<% else %>
<% if table.try(:name) %>
<em><%=t 'projects.reports.elements.step_table.table_name',
name: truncate(table.name,
length: Constants::FILENAME_TRUNCATION_LENGTH) %></em>
<em>
<%= t('projects.reports.elements.step_table.table_name', name: truncate(table.name, length: Constants::FILENAME_TRUNCATION_LENGTH)) %>
</em>
<% end %>
<% end %>
</div>
<div class="pull-left user-time">
<%=t 'projects.reports.elements.step_table.user_time', timestamp: l(timestamp, format: :full) %>
</div>
<div class="pull-right controls">
<%= render partial: 'reports/elements/element_controls.html.erb' %>
<%= t('projects.reports.elements.step_table.user_time', timestamp: l(timestamp, format: :full)) %>
</div>
</div>
</div>

View file

@ -0,0 +1,20 @@
<div class="content-pane" id="report-new">
<div class="report-container">
<!-- Report "preview" -->
<div id="report-content">
<% report.root_elements.each do |el| %>
<%= render_report_element(el, local_assigns) %>
<% end %>
</div>
</div>
</div>
<%= javascript_include_tag "handsontable.full" %>
<!-- Libraries for formulas -->
<%= render partial: "shared/formulas_libraries.html.erb" %>
<%= javascript_include_tag("reports/new") %>
<%= javascript_include_tag 'reports/save_pdf_to_inventory' %>

View file

@ -46,7 +46,7 @@
<%= t("projects.reports.wizard.statuses.step_#{i + 1}") %>
</span>
</div>
<% if @edit %>
<% if @edit && @report.settings["template"].present? %>
<div class="change-step" data-step-id="<%= i + 1 %>">
</div>
<% end %>

View file

@ -1,50 +0,0 @@
<div class="navbar-report">
<div class="center-block" id="report-menu">
<div class="dropdown" id="sort-report">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="fas fa-sort visible-xs-inline"></span>
<span class="hidden-xs"><%= t'projects.reports.new.nav_sort_by' %></span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a href="#" data-sort="desc" data-turbolinks="false"><%= t('projects.reports.new.nav_sort_desc') %></a></li>
<li><a href="#" data-sort="asc" data-turbolinks="false"><%= t('projects.reports.new.nav_sort_asc') %></a></li>
</ul>
</div>
<%= link_to "", class: "btn btn-secondary", remote: true, id: "print-report" do %>
<span class="fas fa-print"></span>
<span class="hidden-xs"><%=t "projects.reports.new.nav_print" %></span>
<% end %>
<div class="dropdown" id="download-report">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="fas fa-download"></span>
<span class="hidden-xs"><%= t("projects.reports.new.nav_download") %><span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
</ul>
</div>
<button
onclick="$('#savePDFtoInventory').modal('show')"
class="btn btn-secondary">
<span class="fas fa-save">
</span>
<%=t 'projects.reports.new.save_PDF_to_inventory'%>
</button>
<div class="pull-right">
<%= link_to reports_path, data: { no_turbolink: false }, id: "cancel-report-link", class: "btn btn-secondary" do %>
<span class="hidden-xs"><%=t "projects.reports.new.nav_close" %></span>
<% end %>
<%= link_to "", class: "btn btn-primary", remote: true, id: "save-report-link" do %>
<span class="hidden-xs"><%=t "projects.reports.new.nav_save" %></span>
<% end %>
</div>
</div>
</div>

View file

@ -1,36 +0,0 @@
<%= bootstrap_form_tag remote: true, url: experiment_contents_project_reports_path(project, format: :json), method: :post, html: { id: "add-contents-form" } do |f| %>
<%= hidden_field_tag :id, experiment.id %>
<div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#tasks-tab" aria-controls="tasks-tab" role="tab" data-toggle="tab">
<span class="fas fa-credit-card visible-xs"></span>
<span class="hidden-xs"><%= t("projects.reports.elements.modals.project_contents.tasks_tab") %></span>
</a>
</li>
<li role="presentation">
<a href="#content-tab" aria-controls="content-tab" role="tab" data-toggle="tab">
<span class="fas fa-link visible-xs"></span>
<span class="hidden-xs"><%= t("projects.reports.elements.modals.project_contents.content_tab") %></span>
</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tasks-tab">
<h5 class="visible-xs"><%= t("projects.reports.elements.modals.project_contents.tasks_tab") %></h5>
<%= render partial: "reports/new/modal/experiment_contents_inner.html.erb", locals: { form: f, experiment: experiment } %>
</div>
<div role="tabpanel" class="tab-pane" id="content-tab">
<h5 class="visible-xs"><%= t("projects.reports.elements.modals.project_contents.content_tab") %></h5>
<%= render partial: "reports/new/modal/module_contents_inner.html.erb", locals: { form: f } %>
<hr>
<%= render partial: "reports/new/modal/step_contents_inner.html.erb", locals: { form: f } %>
<hr>
<%= render partial: "reports/new/modal/result_contents_inner.html.erb", locals: { form: f } %>
</div>
</div>
</div>
<% end %>

View file

@ -1,41 +0,0 @@
<div>
<em>
<%= t("projects.reports.elements.modals.experiment_contents_inner.instructions") %>
</em>
</div>
<% if experiment.my_modules.exists? %>
<div class="checkbox-tree">
<ul>
<li>
<%= form.check_box :experiment_all, label: experiment.name %>
<ul>
<% experiment.my_module_groups.each do |my_module_group| %>
<% if my_module_group.my_modules.exists? then %>
<% my_module_group.my_modules.workflow_ordered.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
<% end %>
<% end %>
<!-- Tasks without groups -->
<% experiment.my_modules.without_group.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
</ul>
</li>
</ul>
</div>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.experiment_contents_inner.no_modules") %>
</em>
</div>
<% end %>

View file

@ -1,26 +0,0 @@
<%= bootstrap_form_tag remote: true, url: module_contents_project_reports_path(project, format: :json), method: :post, html: { id: "add-contents-form" } do |f| %>
<%= hidden_field_tag :id, my_module.id %>
<div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#content-tab" aria-controls="content-tab" role="tab" data-toggle="tab">
<span class="fas fa-link visible-xs"></span>
<span class="hidden-xs"><%= t("projects.reports.elements.modals.project_contents.content_tab") %></span>
</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="content-tab">
<h5 class="visible-xs"><%= t("projects.reports.elements.modals.project_contents.content_tab") %></h5>
<%= render partial: "reports/new/modal/module_contents_inner.html.erb", locals: { form: f } %>
<hr>
<%= render partial: "reports/new/modal/step_contents_inner.html.erb", locals: { form: f } %>
<hr>
<%= render partial: "reports/new/modal/result_contents_inner.html.erb", locals: { form: f } %>
</div>
</div>
</div>
<% end %>

View file

@ -1,79 +0,0 @@
<% my_module_undefined = !defined? my_module or my_module.blank? %>
<div>
<em>
<%= t("projects.reports.elements.modals.module_contents_inner.instructions") %>
</em>
</div>
<div class="checkbox-tree">
<ul data-hook="module-content-list">
<li>
<%= form.check_box :module_all, label: t("projects.reports.elements.modals.module_contents_inner.check_all") %>
<ul>
<li>
<%= form.check_box :module_protocol, label: t("projects.reports.elements.modals.module_contents_inner.protocol") %>
</li>
<% if my_module_undefined or my_module.protocol.steps.exists? %>
<li>
<%= form.check_box :module_steps, label: t("projects.reports.elements.modals.module_contents_inner.steps") %>
<ul>
<li>
<%= form.check_box :module_completed_steps, label: t("projects.reports.elements.modals.module_contents_inner.completed_steps") %>
</li>
<li>
<%= form.check_box :module_uncompleted_steps, label: t("projects.reports.elements.modals.module_contents_inner.uncompleted_steps") %>
</li>
</ul>
</li>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.module_contents_inner.no_steps") %>
</em>
</div>
<% end %>
<% if my_module_undefined or (my_module.results.select { |r| r.active? }).exists? %>
<li>
<%= form.check_box :module_results, label: t("projects.reports.elements.modals.module_contents_inner.results") %>
<ul data-hook="result-types-list">
<% if my_module_undefined or (my_module.results.select { |r| r.is_asset && r.active? }).exists? %>
<li>
<%= form.check_box :module_result_assets, label: t("projects.reports.elements.modals.module_contents_inner.result_assets") %>
</li>
<% end %>
<% if my_module_undefined or (my_module.results.select { |r| r.is_table && r.active? }).exists? %>
<li>
<%= form.check_box :module_result_tables, label: t("projects.reports.elements.modals.module_contents_inner.result_tables") %>
</li>
<% end %>
<% if my_module_undefined or (my_module.results.select { |r| r.is_text && r.active? }).exists? %>
<li>
<%= form.check_box :module_result_texts, label: t("projects.reports.elements.modals.module_contents_inner.result_texts") %>
</li>
<% end %>
</ul>
</li>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.module_contents_inner.no_results") %>
</em>
</div>
<% end %>
<li>
<%= form.check_box :module_activity, label: t("projects.reports.elements.modals.module_contents_inner.activity") %>
</li>
<% assigned_repositories_in_project_list(@project).each do |repository| %>
<li>
<%= form.check_box "module_repository_#{repository.id}", label: repository.name.capitalize, data: { id: repository.id } %>
</li>
<% end %>
</ul>
</li>
</ul>
</div>

View file

@ -1,38 +0,0 @@
<%= bootstrap_form_tag remote: true, url: project_contents_project_reports_path(project, format: :json), method: :post, html: { id: "add-contents-form" } do |f| %>
<%= hidden_field_tag :id, project.id %>
<div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#tasks-tab" aria-controls="tasks-tab" role="tab" data-toggle="tab">
<span class="fas fa-credit-card visible-xs"></span>
<span class="hidden-xs"><%= t("projects.reports.elements.modals.project_contents.tasks_tab") %></span>
</a>
</li>
<% if project.project_my_modules.active.exists? %>
<li role="presentation">
<a href="#content-tab" aria-controls="content-tab" role="tab" data-toggle="tab">
<span class="fas fa-link visible-xs"></span>
<span class="hidden-xs"><%= t("projects.reports.elements.modals.project_contents.content_tab") %></span>
</a>
</li>
<% end %>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tasks-tab">
<h5 class="visible-xs"><%= t("projects.reports.elements.modals.project_contents.tasks_tab") %></h5>
<%= render partial: "reports/new/modal/project_contents_inner.html.erb", locals: { form: f, project: project } %>
</div>
<div role="tabpanel" class="tab-pane" id="content-tab">
<h5 class="visible-xs"><%= t("projects.reports.elements.modals.project_contents.content_tab") %></h5>
<%= render partial: "reports/new/modal/module_contents_inner.html.erb", locals: { form: f } %>
<hr>
<%= render partial: "reports/new/modal/step_contents_inner.html.erb", locals: { form: f } %>
<hr>
<%= render partial: "reports/new/modal/result_contents_inner.html.erb", locals: { form: f } %>
</div>
</div>
</div>
<% end %>

View file

@ -1,49 +0,0 @@
<div>
<em>
<%= t("projects.reports.elements.modals.project_contents_inner.instructions") %>
</em>
</div>
<% if project.project_my_modules.active.exists? %>
<div class="checkbox-tree">
<ul>
<li>
<%= form.check_box :project, label: project.name %>
<ul>
<% project.experiments.includes(:my_module_groups).active.each do |experiment| %>
<% next unless experiment.my_modules.active.exists? %>
<li>
<%= form.check_box "experiment_#{experiment.id}", label: experiment.name %>
<ul>
<% experiment.my_module_groups.each do |my_module_group| %>
<% my_module_group.my_modules.workflow_ordered.active.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
<% end %>
<!-- Tasks without groups -->
<% experiment.my_modules.without_group.each do |my_module| %>
<li>
<%= form.check_box "modules[#{my_module.id}]", label: my_module.name %>
</li>
<% end %>
</ul>
</li>
<% end %>
</ul>
</li>
</ul>
</div>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.project_contents_inner.no_modules") %>
</em>
</div>
<% end %>

View file

@ -1,4 +0,0 @@
<%= bootstrap_form_tag remote: true, url: result_contents_project_reports_path(project, format: :json), method: :post, html: { id: "add-contents-form" } do |f| %>
<%= hidden_field_tag :id, result.id %>
<%= render partial: "reports/new/modal/result_contents_inner.html.erb", locals: { form: f } %>
<% end %>

View file

@ -1,18 +0,0 @@
<div>
<em>
<%= t("projects.reports.elements.modals.result_contents_inner.instructions") %>
</em>
</div>
<div class="checkbox-tree">
<ul>
<li>
<%= form.label :result_all, t("projects.reports.elements.modals.result_contents_inner.check_all"), class: "checkbox" %>
<ul>
<li>
<%= form.check_box :result_comments, label: t("projects.reports.elements.modals.result_contents_inner.comments") %>
</li>
</ul>
</li>
</ul>
</div>

View file

@ -1,5 +0,0 @@
<%= bootstrap_form_for [@project, @report], remote: true, url: @url, method: @method, html: { id: "save-report-form" } do |f| %>
<%= f.text_field :name, label: t("projects.reports.elements.modals.save_report.name"), placeholder: t("projects.reports.elements.modals.save_report.name_placeholder") %>
<%= f.smart_text_area :description, label: t("projects.reports.elements.modals.save_report.description"), placeholder: t("projects.reports.elements.modals.save_report.description_placeholder") %>
<%= hidden_field_tag :report_contents, @report_contents %>
<% end %>

View file

@ -1,4 +0,0 @@
<%= bootstrap_form_tag remote: true, url: step_contents_project_reports_path(project, format: :json), method: :post, html: { id: "add-contents-form" } do |f| %>
<%= hidden_field_tag :id, step.id %>
<%= render partial: "reports/new/modal/step_contents_inner.html.erb", locals: { form: f, step: step } %>
<% end %>

View file

@ -1,58 +0,0 @@
<% step_undefined = !defined? step or step.blank? %>
<div>
<em>
<%= t("projects.reports.elements.modals.step_contents_inner.instructions") %>
</em>
</div>
<div class="checkbox-tree">
<ul>
<li>
<%= form.check_box :step_all, label: t("projects.reports.elements.modals.step_contents_inner.check_all") %>
<ul>
<% if step_undefined or step.checklists.exists? %>
<li>
<%= form.check_box :step_checklists, label: t("projects.reports.elements.modals.step_contents_inner.checklists") %>
</li>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.step_contents_inner.no_checklists") %>
</em>
</div>
<% end %>
<% if step_undefined or step.assets.exists? %>
<li>
<%= form.check_box :step_assets, label: t("projects.reports.elements.modals.step_contents_inner.assets") %>
</li>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.step_contents_inner.no_assets") %>
</em>
</div>
<% end %>
<% if step_undefined or step.tables.exists? %>
<li>
<%= form.check_box :step_tables, label: t("projects.reports.elements.modals.step_contents_inner.tables") %>
</li>
<% else %>
<div>
<em>
<%= t("projects.reports.elements.modals.step_contents_inner.no_tables") %>
</em>
</div>
<% end %>
<li>
<%= form.check_box :step_comments, label: t("projects.reports.elements.modals.step_contents_inner.comments") %>
</li>
</ul>
</li>
</ul>
</div>

View file

@ -1,90 +0,0 @@
<% content_for :head do %>
<meta name="turbolinks-cache-control" content="no-cache">
<meta name="turbolinks-visit-control" content="reload">
<% end %>
<% @settings = @report.settings %>
<% provide(:head_title, t("projects.reports.new.head_title", project: h(@project.name)).html_safe) %>
<%= render partial: "reports/new/report_navigation" %>
<div class="content-pane" id="report-new">
<div class="report-container">
<div
id="data-holder"
class="hidden"
data-project-modal-title="<%=t "projects.reports.elements.modals.project_contents.head_title" %>"
data-add-project-contents-url="<%= project_contents_modal_project_reports_url(@project) %>"
data-add-experiment-contents-url="<%= experiment_contents_modal_project_reports_url(@project) %>"
data-add-module-contents-url="<%= module_contents_modal_project_reports_url(@project) %>"
data-add-step-contents-url="<%= step_contents_modal_project_reports_url(@project) %>"
data-add-result-contents-url="<%= result_contents_modal_project_reports_url(@project) %>"
data-stylesheet-url="<%= stylesheet_path "application" %>"
data-print-title="<%=t "projects.reports.print_title", project: @project.name %>"
data-project-id="<%= @project.id %>"
data-save-report-url="<%= save_modal_project_reports_url(@project) %>"
data-report-id="<%= @report.present? ? @report.id : "" %>"
data-unsaved-work-text="<%=t "projects.reports.new.unsaved_work" %>"
data-global-sort-text="<%=t "projects.reports.new.global_sort" %>"></div>
<!-- Report "preview" -->
<div id="report-content">
<% if @report.present? %>
<% @report.root_elements.each do |el| %>
<%= render_report_element(el, local_assigns) %>
<%= render_new_element(false) %>
<% end %>
<% else %>
<%= render partial: "reports/elements/project_header_element", locals: { project: @project } %>
<%= render partial: "reports/elements/new_element", locals: { initial: true } %>
<% end %>
</div>
<!-- Add elements modal -->
<div class="modal" id="add-contents-modal" tabindex="-1" role="dialog" aria-labelledby="add-contents-modal-label">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="add-contents-modal-label"></h4>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
<button type="button" data-action="add" class="btn btn-primary"><%=t "projects.reports.elements.modals.add" %></button>
</div>
</div>
</div>
</div>
<!-- Save report modal -->
<div class="modal" id="save-report-modal" tabindex="-1" role="dialog" aria-labelledby="save-report-modal-label">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="save-report-modal-label"><%=t "projects.reports.elements.modals.save_report.head_title" %></h4>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
<button type="button" data-action="save" class="btn btn-primary"><%=t "projects.reports.elements.modals.save_report.save" %></button>
</div>
</div>
</div>
</div>
</div>
</div>
<%= javascript_include_tag "handsontable.full" %>
<!-- Libraries for formulas -->
<%= render partial: "shared/formulas_libraries.html.erb" %>
<%= javascript_include_tag("reports/new") %>
<%= javascript_include_tag 'reports/save_pdf_to_inventory' %>

View file

@ -4,7 +4,6 @@
<meta charset='utf-8' />
<%= wicked_pdf_stylesheet_link_tag "application" %>
<%= wicked_pdf_stylesheet_link_tag "reports_pdf" %>
<%= bootstrap_cdn_link_tag %>
<%= font_awesome_cdn_link_tag %>
<%= wicked_pdf_javascript_include_tag "jquery" %>
<%= wicked_pdf_javascript_include_tag "handsontable.full" %>
@ -25,7 +24,6 @@
<div class="print-report">
<% report.root_elements.each do |el| %>
<%= render_report_element(el, local_assigns) %>
<%= render_new_element(false) %>
<% end %>
</div>

View file

@ -21,7 +21,7 @@
</style>
<div class="print-header">
<div class="logo-img">
<%= image_tag wicked_pdf_asset_base64('logo.png') %>
<%= wicked_pdf_image_tag logo %>
</div>
<div class="page-numbers pagination" data-page-offset="0">
Page <span class="page"></span> of <span class="topage"></span>

View file

@ -1,5 +1,5 @@
<div class="project-selector-container">
<%= render partial: 'reports/wizard/project_template_selector', locals: {report: report} %>
</div>
<div class="report-template-values-container <%= 'hidden' if report.new_record? %>">
<div class="report-template-values-container <%= 'hidden' if report.settings["template"].blank? %>">
</div>

View file

@ -17,7 +17,7 @@
options_for_select(@templates.invert, @active_template),
prompt: t('projects.reports.wizard.first_step.select_template'),
data: {
disable_on_load: report.settings[:template].blank?,
disable_on_load: report.settings[:template].blank? && report.new_record?,
placeholder: t('projects.reports.wizard.first_step.select_template'),
selected_template: report.settings[:template],
values_editor_path: reports_new_template_values_path(report_id: report.id)

View file

@ -69,10 +69,24 @@
<% @repositories.each do |repository| %>
<li>
<span class="sci-checkbox-container">
<input type="checkbox" class="sci-checkbox repositories-setting" value="<%= repository.id %>" <%= 'checked' if report.new_record? || @project_contents[:repositories].include?(repository.id) %> />
<input type="checkbox"
class="sci-checkbox repositories-setting"
value="<%= repository.id %>"
<%= 'checked' if report.new_record? ||
@project_contents[:repositories].include?(repository.id) ||
(repository.is_a?(Repository) && repository.repository_snapshots.exists?(id: @project_contents[:repositories])) %> />
<span class="sci-checkbox-label"></span>
</span>
<%= repository.name %>
<% if repository.archived? %>
<span class="archived">
<%= t("projects.reports.wizard.third_step.archived") %>
</span>
<% elsif repository.is_a?(RepositorySnapshot) %>
<span class="deleted">
<%= t("projects.reports.wizard.third_step.deleted") %>
</span>
<% end %>
<div class="divider"></div>
</li>
<% end %>

View file

@ -94,9 +94,12 @@
<span><%= t('left_menu_bar.support') %></span>
</a>
<ul class="dropdown-menu" data-hook="support-dropdown">
<li><%= link_to t('left_menu_bar.support_links.support'),
Constants::SUPPORT_URL,
target: "_blank" %></li>
<li>
<%= link_to Constants::SUPPORT_URL, target: "_blank", id: "knowledge-center-link" do %>
<i class="fas fa-question-circle"></i>
<%= t('left_menu_bar.support_links.support') %>
<% end %>
</li>
<li><%= link_to t('left_menu_bar.support_links.tutorials'),
Constants::TUTORIALS_URL,
target: "_blank" %></li>

View file

@ -21,7 +21,7 @@
<% if @notification.system_message? %>
<% # We assume the system notification is clean %>
<%= @notification.message.html_safe %>
<% elsif @notification.deliver? %>
<% elsif @notification.deliver? && @notification.message.match?(/data-id=('|")(\d*)('|")/) %>
<%= I18n.t("notifications.deliver.download_link") %>
<% # work around the problem with inserting the link of zipExport %>
<% zip_id = /data-id=('|")(\d*)('|")/.match(@notification.message)[2] %>

View file

@ -31,7 +31,7 @@
<div class="date-format-selector-container">
<%= select_tag "date-format-input-field",
options_for_select(
Constants::SUPPORTED_DATE_FORMATS.uniq.map{ |df|
Constants::SUPPORTED_DATE_FORMATS.map { |df|
["#{l(Time.new(2019, 11, 25), format: :full_date, date_format: df)}", df]
},
@user.settings[:date_format]

View file

@ -42,83 +42,7 @@ class Extends
my_module_repository: 17,
my_module_protocol: 18 }
EXPORT_ALL_PROJECT_ELEMENTS = [
{
type_of: 'project_header',
id_key: 'project_id'
},
{
type_of: 'experiment',
id_key: 'experiment_id',
relation: %w(experiments),
children: [
{
type_of: 'my_module',
id_key: 'my_module_id',
relation: %w(my_modules),
children: [
{
type_of: 'my_module_protocol',
id_key: 'my_module_id'
},
{
type_of: 'step',
relation: %w(protocol steps),
id_key: 'step_id',
children: [
{
type_of: 'step_asset',
relation: %w(assets),
id_key: 'asset_id'
},
{
type_of: 'step_table',
relation: %w(tables),
id_key: 'table_id'
},
{
type_of: 'step_checklist',
relation: %w(checklists),
id_key: 'checklist_id'
},
{
type_of: 'step_comments',
id_key: 'step_id',
sort_order: 'asc'
}
]
},
{
type_of_lambda: lambda { |result|
(result.result_asset ||
result.result_table ||
result.result_text).class.to_s.underscore
},
relation: %w(results),
id_key: 'result_id',
children: [{
type_of: 'result_comments',
id_key: 'result_id',
sort_order: 'asc'
}]
},
{
type_of: 'my_module_activity',
id_key: 'my_module_id',
sort_order: 'asc'
},
{
type_of: 'my_module_repository',
relation: %w(experiment project assigned_repositories_and_snapshots),
id_key: 'repository_id',
parent_id_key: 'my_module_id',
sort_order: 'asc'
}
]
}
]
}
]
ACTIVE_REPORT_ELEMENTS = %i(project_header my_module experiment my_module_repository)
# Data type name should match corresponding model's name
REPOSITORY_DATA_TYPES = { RepositoryTextValue: 0,
@ -143,16 +67,25 @@ class Extends
REPOSITORY_IMPORT_COLUMN_PRELOADS = %i(repository_list_items repository_status_items repository_checklist_items)
# Extra attributes used for search in repositories, 'filed_name' => include_hash
REPOSITORY_EXTRA_SEARCH_ATTR = {'repository_text_values.data' => :repository_text_value,
'repository_number_values.data' => :repository_number_value,
'repository_list_items.data' => { repository_list_value: :repository_list_item },
'repository_checklist_items.data' =>
{ repository_checklist_value:
{ repository_checklist_items_values: :repository_checklist_item } },
'repository_status_items.status' =>
{ repository_status_value: :repository_status_item },
'active_storage_blobs.filename' =>
{ repository_asset_value: { asset: { file_attachment: :blob } } } }
REPOSITORY_EXTRA_SEARCH_ATTR = {
RepositoryTextValue: {
field: 'repository_text_values.data', includes: :repository_text_value
}, RepositoryNumberValue: {
field: 'repository_number_values.data', includes: :repository_number_value
}, RepositoryListValue: {
field: 'repository_list_items.data',
includes: { repository_list_value: :repository_list_item }
}, RepositoryChecklistValue: {
field: 'repository_checklist_items.data',
includes: { repository_checklist_value: { repository_checklist_items_values: :repository_checklist_item } }
}, RepositoryStatusValue: {
field: 'repository_status_items.status',
includes: { repository_status_value: :repository_status_item }
}, RepositoryAssetValue: {
field: 'active_storage_blobs.filename',
includes: { repository_asset_value: { asset: { file_attachment: :blob } } }
}
}
# Array of includes used in search query for repository rows
REPOSITORY_SEARCH_INCLUDES = [:repository_text_value,

View file

@ -1,227 +0,0 @@
#########################################################
# EXTENDS METHODS. Here you can extend the arrays, #
# hashes,.. which is used in methods. Please specify #
# the method name and location! #
#########################################################
module ReportExtends
# path: app/controllers/concerns/ReportActions
# method: generate_module_contents_json
# ModuleElement struct creates an argument objects which is needed in
# generate_module_contents_json method. It takes 3 parameters a Proc and
# additional options wich can be extended.
# :values => name of the hook/identifier for specific module element state
# :element => name of module element in plural
# :children => bolean if element has children elements in report
# :locals => an array of names of local variables which are passed in the view
# :coll => a procedure which the my_module is passed and have to return a
# collection of elements
# :singular => true by defaut; change the enum type to singular - needed when
# querying partials by name
# :has_many => false by default; whether the element can have many
# manifestations, and its id will be appended.
ModuleElement = Struct.new(:values,
:element,
:children,
:locals,
:coll,
:singular,
:has_many) do
def initialize(values,
element,
children,
locals,
coll = nil,
singular = true,
has_many = false)
super(values, element, children, locals, coll, singular, has_many)
end
def collection(my_module, params2)
coll.call(my_module, params2) if coll
end
def parse_locals(values)
container = {}
locals.each_with_index do |local, index|
container[local] = values[index]
end
container
end
def file_name
return element.to_s unless singular
element.to_s.singularize
end
end
ACTIVE_REPORT_ELEMENTS = %i(project_header my_module project_activity experiment my_module_repository)
# Module contents element
MODULE_CONTENTS = [
ModuleElement.new([:protocol],
:protocol,
false,
[:my_module]),
ModuleElement.new(%i(completed_steps uncompleted_steps),
:steps,
true,
[:step],
proc do |my_module, params2|
steps = []
steps << true if params2["module_completed_steps"] == '1'
steps << false if params2["module_uncompleted_steps"] == '1'
my_module.protocol.steps.where(completed: steps).order(:position)
end),
ModuleElement.new([:result_assets],
:result_assets,
true,
[:result],
proc do |my_module|
my_module.results.joins(:result_asset).select(&:active?)
end),
ModuleElement.new([:result_tables],
:result_tables,
true,
[:result],
proc do |my_module|
my_module.results.joins(:result_table).select(&:active?)
end),
ModuleElement.new([:result_texts],
:result_texts,
true,
[:result],
proc do |my_module|
my_module.results.joins(:result_text).select(&:active?)
end),
ModuleElement.new([:activity],
:activity,
false,
%i(my_module order)),
ModuleElement.new([:repository],
:repository,
false,
%i(my_module order),
nil,
true,
true)
]
# path: app/helpers/reports_helpers.rb
# method: render_report_element
# sets local :my_module to the listed my_module child elements
MY_MODULE_ELEMENTS = %w(my_module
my_module_protocol
my_module_activity
my_module_repository)
# sets local name to first element of the listed elements
FIRST_PART_ELEMENTS = %w(result_comments
result_text
result_asset
result_table
project_header
step_comments)
MY_MODULE_CHILDREN_ELEMENTS = %w(step result_asset result_table result_text)
# path: app/models/report_element.rb
# method: set_element_reference
ElementReference = Struct.new(:checker, :elements) do
def initialize(checker, elements = :element_reference_needed!)
super(checker, elements)
end
def check(report_element)
checker.call(report_element)
end
end
SET_ELEMENT_REFERENCES_LIST = [
ElementReference.new(
proc do |report_element|
report_element.project_header?
end,
['project_id']
),
ElementReference.new(proc(&:experiment?), ['experiment_id']),
ElementReference.new(
proc do |report_element|
report_element.my_module? ||
report_element.my_module_protocol? ||
report_element.my_module_activity?
end,
['my_module_id']
),
ElementReference.new(
proc(&:my_module_repository?),
%w(my_module_id repository_id)
),
ElementReference.new(
proc do |report_element|
report_element.step? || report_element.step_comments?
end,
['step_id']
),
ElementReference.new(
proc do |report_element|
report_element.result_asset? ||
report_element.result_table? ||
report_element.result_text? ||
report_element.result_comments?
end,
['result_id']
),
ElementReference.new(proc(&:step_checklist?), ['checklist_id']),
ElementReference.new(proc(&:step_asset?), ['asset_id']),
ElementReference.new(proc(&:step_table?), ['table_id'])
]
# path: app/models/report_element.rb
# method: element_reference
ELEMENT_REFERENCES = [
ElementReference.new(
proc do |report_element|
report_element.project_header?
end,
['project_id']
),
ElementReference.new(proc(&:experiment?), ['experiment_id']),
ElementReference.new(
proc do |report_element|
report_element.my_module? ||
report_element.my_module_protocol? ||
report_element.my_module_activity?
end,
['my_module_id']
),
ElementReference.new(
proc(&:my_module_repository?),
%w(my_module_id repository_id)
),
ElementReference.new(
proc do |report_element|
report_element.step? ||
report_element.step_comments?
end,
['step_id']
),
ElementReference.new(
proc do |report_element|
report_element.result_asset? ||
report_element.result_table? ||
report_element.result_text? ||
report_element.result_comments?
end,
['result_id']
),
ElementReference.new(proc(&:step_checklist?), ['checklist_id']),
ElementReference.new(proc(&:step_asset?), ['asset_id']),
ElementReference.new(proc(&:step_table?), ['table_id'])
]
end

View file

@ -65,7 +65,7 @@ en:
linkedin:
provider_name: "LinkedIn"
complete_sign_up: "You have to complete the sign up process"
email_already_taken: "SciNote account with email %{email} alreday exists"
email_already_taken: "SciNote account with email %{email} already exists"
failed_to_save: "Failed to create new user"
azure:
provider_name: "Azure Active Directory"
@ -315,7 +315,7 @@ en:
edit: "Edit"
delete: "Delete"
delete_confirm: "Are you sure you wish to delete this comment?"
delete_error: "Error occured while deleting comment."
delete_error: "Error occurred while deleting comment."
projects:
index:
@ -352,7 +352,7 @@ en:
manage_users: "Manage users"
no_notifications: "There are no overdue tasks at the moment"
no_results_found: "No results found..."
no_results_description: "Try resetting your filter or choose a different search querry"
no_results_description: "Try resetting your filter or choose a different search query"
module_overdue_html: "Task <em>%{module}</em> is overdue (%{days})."
module_overdue_days:
one: "1 day"
@ -381,7 +381,7 @@ en:
archive_option: "Archive"
archive_confirm: "Are you sure you want to archive this project?"
restore_option: "Restore"
comments_option: "Show commments (%{comments_count})"
comments_option: "Show comments (%{comments_count})"
activities_option: "Open activities"
comment_placeholder: "Your Message"
more_comments: "More Comments"
@ -474,7 +474,7 @@ en:
error_flash: "Project <strong>%{name}</strong> not archived."
archive_group:
success_flash: "<strong>%{number}</strong> project(s) successfully archived."
error_flash: "Failed to arhive project(s)."
error_flash: "Failed to archive project(s)."
restore_group:
success_flash: "<strong>%{number}</strong> project(s) successfully restored."
error_flash: "Failed to restore project(s)."
@ -518,7 +518,7 @@ en:
regeneration_modal_title: "Report content"
regeneration_modal_body: "The content of Project, Experiments and Tasks included in this report might have been updated in SciNote since the report was last generated. Therefore the content of the report you are about to generate might be different from the saved version."
regeneration_modal_confirmation: "Do you want to continue?"
accepted_message: "Your report is succesfully added to the generator queue. We will notify you when it is done!"
accepted_message: "Your report is successfully added to the generator queue. We will notify you when it is done!"
completed_docx_notification_title: "Your report .DOCX was generated successfully."
completed_pdf_notification_title: "Your report .PDF was generated successfully."
completed_notification_message: "Report: %{report_link} | Team: %{team_name}"
@ -548,8 +548,8 @@ en:
header: "Header"
cover: "Title page"
footer: "Footer"
no_values_title: "No additional data requiered"
no_values_description: "SciNote template doesnt need any additional input for it to be succesfully generated."
no_values_title: "No additional data required"
no_values_description: "SciNote template doesnt need any additional input for it to be successfully generated."
second_step:
select_project_content: "Select and reorder experiments and tasks"
collapse_all: "Collapse all"
@ -586,6 +586,8 @@ en:
results_comments: "Include all result comments"
additional_content: "Additional content"
task_activity: "Include task activity"
archived: "[archived]"
deleted: "[deleted]"
new:
report_name_placeholder: "Name your report"
@ -593,7 +595,7 @@ en:
generate_button: "Start generating"
generate_as_button: "Generate as"
save_as_new_report: "A new report"
update_report: "Overwrite current reprot"
update_report: "Overwrite current report"
head_title: "%{project} | New report"
nav_title: "Report for: "
nav_print: "Print"
@ -642,7 +644,7 @@ en:
confirmation: "Do you want to continue?"
project_warning_modal:
title: "Task selection will refresh"
description: "Youre about to switch to a different project. The task selections you made will be completly refreshed."
description: "Youre about to switch to a different project. The task selections you made will be completely refreshed."
confirmation: "Do you want to continue?"
generate_PDF:
generated_on: "Report generated by SciNote on: %{timestamp}"
@ -652,71 +654,6 @@ en:
appended_table: "Appended table"
elements:
download: "[Download]"
modals:
project_contents:
head_title: "Add contents to report"
tasks_tab: "Choose tasks"
content_tab: "Choose content"
project_contents_inner:
instructions: "To create a project report select one or multiple experiment. You can include an entire experiment or individual experimental tasks."
no_modules: "The project contains no tasks"
no_module_group: "No workflow"
module_contents:
head_title: "Add contents to task %{module}"
module_tab: "Task content"
steps_tab: "Protocols content"
results_tab: "Results content"
module_contents_inner:
instructions: "Select the information from your task that you would like to include to your report."
check_all: "All tasks content"
protocol: "Protocol"
steps: "Steps"
completed_steps: "Completed"
uncompleted_steps: "Uncompleted"
no_steps: "Task has no steps"
results: "Results"
result_assets: "Files"
result_tables: "Tables"
result_texts: "Texts"
no_results: "Task contains no results"
activity: "Activity"
experiment_contents:
head_title: "Add contents to experiment %{experiment}"
experiment_tab: "Experiment content"
module_tab: "Task content"
steps_tab: "Protocols content"
results_tab: "Results content"
experiment_contents_inner:
instructions: "Select tasks to include in the report"
no_modules: "The experiment contains no tasks"
step_contents:
head_title: "Add contents to step %{step}"
step_tab: "Step content"
results_tab: "Results content"
step_contents_inner:
instructions: "Select the information from task protocol step/s to include in the report"
check_all: "All protocols steps content"
tables: "Tables"
no_tables: "Step contains no tables"
assets: "Files"
no_assets: "Step contains no uploaded files"
checklists: "Checklists"
no_checklists: "Step contains no checklists"
comments: "Comments"
result_contents:
head_title: "Add contents to result %{result}"
result_contents_inner:
instructions: "Include result/s comments in the report?"
check_all: "All results content"
comments: "Comments"
add: "Add"
save_report:
head_title: "Save report"
name: "Report name"
name_placeholder: "My report"
description: "Report description"
description_placeholder: "My report description..."
save: "Save"
all:
sort_asc: "Sort report element contents by oldest on top"
sort_desc: "Sort report element contents by newest on top"
@ -724,8 +661,6 @@ en:
move_down: "Move report element down"
remove: "Remove report element from the report"
scinote_link: "SciNote link"
new_element:
title: "Add new report element/s here"
project_header:
user_time: "Project created on %{timestamp}."
title: "Report for project %{project}"
@ -824,7 +759,7 @@ en:
update_role: "Change Role"
create:
select_user_role: "Please select a user role."
add_user_generic_error: "An error occured. "
add_user_generic_error: "An error occurred. "
can_add_user_to_project: "Can not add user to the project."
my_modules:
@ -882,7 +817,7 @@ en:
head_title: "%{project} | %{module} | Archive"
option_delete: "Delete"
confirm_delete: "Are you sure you want to permanently delete result?"
delete_flash: "Sucessfully removed result <strong>%{result}</strong> from task <strong>%{module}</strong>."
delete_flash: "Successfully removed result <strong>%{result}</strong> from task <strong>%{module}</strong>."
archived_on: "Archived on"
archived_on_title: "Result archived on %{date} at %{time}."
option_download: "Download"
@ -906,7 +841,7 @@ en:
template_updated: "Template updated on:"
protocol_updated: "Protocol updated on:"
messages:
template_updated_html: "There is a new version of this protocol avaliable in the protocol repository.<br>Would you like to update it?"
template_updated_html: "There is a new version of this protocol available in the protocol repository.<br>Would you like to update it?"
protocol_updated: "The version of this protocol in the task is modified, do you wish to save it as a new protocol template?"
unlinked: "This protocol is not linked to the repository."
btns:
@ -1063,7 +998,7 @@ en:
description: 'Try another search request'
unshared_inventory:
title_html: The inventory <b>%{inventory_name}</b> is no longer shared with your team.
body_html: This inventory has been ushared with your team by the inventorys owner. To view the item/s that are assigned to your task/s contact the <b>%{team_name}</b> team administrator <b>%{admin_name}</b> (<b>%{admin_email}</b>).
body_html: This inventory has been unshared with your team by the inventorys owner. To view the item/s that are assigned to your task/s contact the <b>%{team_name}</b> team administrator <b>%{admin_name}</b> (<b>%{admin_email}</b>).
open_mobile_app: "Open mobile app"
experiments:
header:
@ -1300,7 +1235,7 @@ en:
wopi_edit_file: "Edit in %{app}"
wopi_word: "Word for the web"
wopi_excel: "Excel for the web"
wopi_powerpoint: "Powerpoint for the web"
wopi_powerpoint: "PowerPoint for the web"
error_flash: 'Something went wrong! Please try again later.'
result_tables:
@ -1344,7 +1279,7 @@ en:
columns: "Columns"
edit_inventory: "Edit Inventory"
share_inventory: "Share"
view_only_permission_label: "You have veiw-only permission"
view_only_permission_label: "You have view-only permission"
show_per_page: "Show %{number} per page"
filter_inventory: "Filter inventories"
no_inventories: "No inventories here"
@ -1517,7 +1452,7 @@ en:
js:
permission_error: "You don't have permission to edit this item."
not_found_error: "This inventory item does not exist."
column_added: "New column was sucessfully created."
column_added: "New column was successfully created."
empty_column_name: "Please enter column name."
create:
success_flash: "Successfully added item <strong>%{record}</strong> to inventory <strong>%{repository}</strong>"
@ -1797,7 +1732,7 @@ en:
next: "Next"
step_3:
title: "3. Enter the code given by your authenticator app"
description: "Enter the generated code into the fields below to finalize the setup of the two-factor authorisation."
description: "Enter the generated code into the fields below to finalize the setup of the two-factor authorization."
enter_code: "Enter authenticator code"
verify: "Verify"
step_4:
@ -1807,7 +1742,7 @@ en:
download_codes: "Download codes"
disable:
title: "Disable two-factor authentication"
description: "Enter your password below to confirm disableing 2FA. This will remove authentication, from your account and make you more vulnerable to potential attacks."
description: "Enter your password below to confirm disabling 2FA. This will remove authentication, from your account and make you more vulnerable to potential attacks."
password_label: "Enter password"
disable_2fa: "Disable 2FA"
2fa_errors:
@ -1863,7 +1798,7 @@ en:
head_title: "Settings | Connected Accounts"
title: "Connected Accounts"
not_connected: "You have no Connected accounts"
unlink_success: "Sucessfully unlinked"
unlink_success: "Successfully unlinked"
azure_ad:
title: "Your Azure AD Account"
connect_hint: "Allows you to sign in with your Azure AD account."
@ -1951,7 +1886,7 @@ en:
destroy_uo_alert_line_3: "all repository protocols in the team belonging to user will be reassigned onto you;"
destroy_uo_alert_line_4: "all inventory items in the team added by user will be reassigned onto you."
destroy_uo_confirm: "Remove"
leave_flash: "Successfuly left team %{team}."
leave_flash: "Successfully left team %{team}."
protocols:
protocols_io_import:
@ -2106,13 +2041,13 @@ en:
description: "Archived protocols can only be seen by you. Restoring protocols will return them to their previous location (team/my protocols)."
restore: "Restore"
make_private_unauthorized: "You do not have permission to move selected protocols to My protocols."
make_private_error: "Error occured while moving selected protocols to My protocols."
make_private_error: "Error occurred while moving selected protocols to My protocols."
publish_unauthorized: "You do not have permission to move selected protocols to Team protocols."
publish_error: "Error occured while moving selected protocols to Team protocols."
publish_error: "Error occurred while moving selected protocols to Team protocols."
archive_unauthorized: "You do not have permission to archive selected protocols."
archive_error: "Error occured while archiving selected protocols."
archive_error: "Error occurred while archiving selected protocols."
restore_unauthorized: "You do not have permission to restore selected protocols."
restore_error: "Error occured while restoring selected protocols."
restore_error: "Error occurred while restoring selected protocols."
row_renamed_html: "%{old_name}<i> to </i>%{new_name}"
no_protocol_name: "(no name)"
create:
@ -2286,7 +2221,7 @@ en:
user_exists_unconfirmed_invited_to_team: "User is already a member of SciNote but is not confirmed yet - successfully invited to team %{team} as %{role}."
user_exists_and_in_team: "User is already a member of SciNote and team %{team} as %{role}."
user_exists_invited_to_team: "User was already a member of SciNote - successfully invited to team %{team} as %{role}."
user_created: "User succesfully invited to SciNote."
user_created: "User successfully invited to SciNote."
user_created_invited_to_team: "User successfully invited to SciNote and team %{team} as %{role}."
user_invalid: "Invalid email."
too_many_emails: "Only invited first %{nr} emails. To invite more users, "
@ -2379,7 +2314,7 @@ en:
size_label: "Size: %{size}"
wopi_supported_text_formats_title: 'Only .docx, .docm, .odt file formats are supported for editing in Word Online.'
wopi_supported_table_formats_title: 'Only .xlsx, .xlsm, .xlsb, .ods file formats are supported for editing in Excel Online.'
wopi_supported_presentation_formats_title: 'Only .pptx, ppsx, .odp file formats are supported for editing in Powerpoint Online.'
wopi_supported_presentation_formats_title: 'Only .pptx, ppsx, .odp file formats are supported for editing in PowerPoint Online.'
create_wopi_file:
button_text: 'New Office file'
li_text: "Office file"
@ -2624,8 +2559,8 @@ en:
generic_error_message: "Something went wrong! Please try again later."
user_teams:
permission_error: "You don't have permission to manage users."
leave_team_error: "An error occured."
leave_flash: "Successfuly left team %{team}."
leave_team_error: "An error occurred."
leave_flash: "Successfully left team %{team}."
teams:
create_permission_error: "You don't have permission to create team."
update_permission_error: "You don't have permission to edit this team."

View file

@ -255,42 +255,7 @@ Rails.application.routes.draw do
end
collection do
# The posts following here should in theory be gets,
# but are posts because of parameters payload
get 'new/', to: 'reports#new'
get 'new/project_contents_modal',
to: 'reports#project_contents_modal',
as: :project_contents_modal
post 'new/project_contents',
to: 'reports#project_contents',
as: :project_contents
get 'new/experiment_contents_modal',
to: 'reports#experiment_contents_modal',
as: :experiment_contents_modal
post 'new/experiment_contents',
to: 'reports#experiment_contents',
as: :experiment_contents
get 'new/module_contents_modal',
to: 'reports#module_contents_modal',
as: :module_contents_modal
post 'new/module_contents',
to: 'reports#module_contents',
as: :module_contents
get 'new/step_contents_modal',
to: 'reports#step_contents_modal',
as: :step_contents_modal
post 'new/step_contents',
to: 'reports#step_contents',
as: :step_contents
get 'new/result_contents_modal',
to: 'reports#result_contents_modal',
as: :result_contents_modal
post 'new/result_contents',
to: 'reports#result_contents',
as: :result_contents
post '_save',
to: 'reports#save_modal',
as: :save_modal
get 'new', to: 'reports#new'
end
end
resources :experiments, only: %i(new create), defaults: { format: 'json' } do

View file

@ -7234,6 +7234,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210312185911'),
('20210325152257'),
('20210407143303'),
('20210410100006'),
('20210506125657');

View file

@ -3,8 +3,18 @@
class CustomI18nBackend < I18n::Backend::Simple
attr_accessor :date_format
# Gets I18n configuration object.
def date_format
Thread.current[:i18n_date_format] ||= Constants::DEFAULT_DATE_FORMAT
end
# Sets I18n configuration object.
def date_format=(value)
Thread.current[:i18n_date_format] = value
end
def localize(locale, object, format = :default, options = {})
options[:date_format] ||= @date_format || Constants::DEFAULT_DATE_FORMAT
options[:date_format] ||= date_format
super(locale, object, format, options)
end
end

View file

@ -369,10 +369,11 @@ RSpec.describe 'Api::V1::InventoryCellsController', type: :request do
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells,
each_serializer: Api::V1::InventoryCellSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells, each_serializer: Api::V1::InventoryCellSerializer)
.to_json
)['data']
)
end
@ -548,10 +549,11 @@ RSpec.describe 'Api::V1::InventoryCellsController', type: :request do
expect(response).to have_http_status 201
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(RepositoryCell.last,
serializer: Api::V1::InventoryCellSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(RepositoryCell.last, serializer: Api::V1::InventoryCellSerializer)
.to_json
)['data']
)
end
@ -602,10 +604,11 @@ RSpec.describe 'Api::V1::InventoryCellsController', type: :request do
expect(response).to have_http_status 201
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(RepositoryCell.last,
serializer: Api::V1::InventoryCellSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(RepositoryCell.last, serializer: Api::V1::InventoryCellSerializer)
.to_json
)['data']
)
end
@ -836,10 +839,12 @@ RSpec.describe 'Api::V1::InventoryCellsController', type: :request do
expect(response).to have_http_status 200
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells.where(repository_column: @date_column).first,
serializer: Api::V1::InventoryCellSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells.where(repository_column: @date_column).first,
serializer: Api::V1::InventoryCellSerializer)
.to_json
)['data']
)
end
@ -872,10 +877,12 @@ RSpec.describe 'Api::V1::InventoryCellsController', type: :request do
expect(response).to have_http_status 200
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells.where(repository_column: @date_time_column).first,
serializer: Api::V1::InventoryCellSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells.where(repository_column: @date_time_column).first,
serializer: Api::V1::InventoryCellSerializer)
.to_json
)['data']
)
end
@ -890,10 +897,12 @@ RSpec.describe 'Api::V1::InventoryCellsController', type: :request do
expect(response).to have_http_status 200
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells.where(repository_column: @date_range_column).first,
serializer: Api::V1::InventoryCellSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_item.repository_cells.where(repository_column: @date_range_column).first,
serializer: Api::V1::InventoryCellSerializer)
.to_json
)['data']
)
end

View file

@ -33,10 +33,11 @@ RSpec.describe 'Api::V1::ProjectsController', type: :request do
headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@teams.first.projects,
each_serializer: Api::V1::ProjectSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@teams.first.projects, each_serializer: Api::V1::ProjectSerializer)
.to_json
)['data']
)
end
@ -66,10 +67,11 @@ RSpec.describe 'Api::V1::ProjectsController', type: :request do
headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@teams.first.projects.first,
serializer: Api::V1::ProjectSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@teams.first.projects.first, serializer: Api::V1::ProjectSerializer)
.to_json
)['data']
)
end

View file

@ -20,10 +20,9 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
last_modified_by: @user, project: @valid_project)
@unaccessible_experiment = create(:experiment, created_by: @user,
last_modified_by: @user, project: @unaccessible_project)
create_list(:my_module, 3, created_by: @user,
create_list(:my_module, 3, :with_due_date, created_by: @user,
last_modified_by: @user, experiment: @valid_experiment)
create_list(:my_module, 3, created_by: @user,
create_list(:my_module, 3, :with_due_date, created_by: @user,
last_modified_by: @user, experiment: @unaccessible_experiment)
@valid_headers =
@ -40,10 +39,11 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@valid_experiment.my_modules,
each_serializer: Api::V1::TaskSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_experiment.my_modules, each_serializer: Api::V1::TaskSerializer)
.to_json
)['data']
)
end
@ -95,10 +95,11 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
), headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data]).to match(
ActiveModelSerializers::SerializableResource
.new(@valid_experiment.my_modules.first,
serializer: Api::V1::TaskSerializer)
.as_json[:data]
JSON.parse(
ActiveModelSerializers::SerializableResource
.new(@valid_experiment.my_modules.first, serializer: Api::V1::TaskSerializer)
.to_json
)['data']
)
end