Merge branch 'master' of https://github.com/biosistemika/scinote-web into zd_SCI_765

This commit is contained in:
zmagod 2017-03-27 10:41:58 +02:00
commit 0996c14449
36 changed files with 856 additions and 547 deletions

View file

@ -68,8 +68,6 @@ gem 'tinymce-rails' # Rich text editor
gem 'base62' # Used for smart annotations
gem 'nokogiri' # XML parser
group :development, :test do
gem 'byebug'
gem 'better_errors'

View file

@ -224,6 +224,32 @@ var HelperModule = (function(){
}
}
helpers.flashAlertMsg = function(message, type) {
var alertType;
var glyphSign;
$('#notifications').html('');
if (type === 'success') {
alertType = ' alert-success ';
glyphSign = ' glyphicon-ok-sign ';
} else if (type === 'danger') {
alertType = ' alert-danger ';
glyphSign = ' glyphicon-exclamation-sign ';
}
var htmlSnippet = '<div class="alert alert' + alertType +
'alert-dismissable alert-floating">' +
'<div class="container">' +
'<button type="button" class="close" ' +
'data-dismiss="alert" aria-label="Close">' +
'<span aria-hidden="true">×</span></button>' +
'<span class="glyphicon' + glyphSign + '"></span>' +
'<span>' + message + '</span>' +
'</div>' +
'</div>';
$('#notifications').html(htmlSnippet);
$('#content-wrapper').addClass('alert-shown');
helpers.hideFlashMsg();
}
$( document ).ready(function() {
helpers.treeLinkTruncation();
helpers.hideFlashMsg();

View file

@ -503,7 +503,9 @@ function onClickEdit() {
},
error: function (e, data, status, xhr) {
if (e.status == 403) {
sampleAlertMsg(I18n.t("samples.js.permission_error"), "danger");
HelperModule.flashAlertMsg(
I18n.t('samples.js.permission_error'), 'danger'
);
changeToViewMode();
updateButtons();
}
@ -565,7 +567,7 @@ function onClickSave() {
dataType: "json",
data: data,
success: function (data) {
sampleAlertMsg(data.flash, "success");
HelperModule.flashAlertMsg(data.flash, 'success');
onClickCancel();
},
error: function (e, eData, status, xhr) {
@ -573,12 +575,16 @@ function onClickSave() {
clearAllErrors();
if (e.status == 404) {
sampleAlertMsg(I18n.t("samples.js.not_found_error"), "danger");
HelperModule.flashAlertMsg(
I18n.t('samples.js.not_found_error'), 'danger'
);
changeToViewMode();
updateButtons();
}
else if (e.status == 403) {
sampleAlertMsg(I18n.t("samples.js.permission_error"), "danger");
HelperModule.flashAlertMsg(
I18n.t('samples.js.permission_error'), 'danger'
);
changeToViewMode();
updateButtons();
}
@ -794,7 +800,9 @@ function onClickAddSample() {
},
error: function (e, eData, status, xhr) {
if (e.status == 403)
sampleAlertMsg(I18n.t("samples.js.permission_error"), "danger");
HelperModule.flashAlertMsg(
I18n.t('samples.js.permission_error'), 'danger'
);
changeToViewMode();
updateButtons();
}
@ -967,6 +975,7 @@ function changeToEditMode() {
'<th class="custom-field" id="' + data.id + '" ' +
'data-editable data-deletable ' +
'data-edit-url="' + data.edit_url + '" ' +
'data-update-url="' + data.update_url + '" ' +
'data-destroy-html-url="' + data.destroy_html_url + '"' +
'>' + generateColumnNameTooltip(data.name) + '</th>');
@ -1050,6 +1059,7 @@ function changeToEditMode() {
'data-position="' + colIndex + '" ' +
'data-id="' + $(el).attr('id') + '" ' +
'data-edit-url=' + $(el).attr('data-edit-url') + ' ' +
'data-update-url=' + $(el).attr('data-update-url') + ' ' +
'data-destroy-html-url=' + $(el).attr('data-destroy-html-url') + ' ' +
'class="' + visLi + '"' +
'>' +
@ -1151,7 +1161,7 @@ function changeToEditMode() {
var text = li.find('.text');
var textEdit = li.find('.text-edit');
var newName = textEdit.val().trim();
var url = li.attr('data-edit-url');
var url = li.attr('data-update-url');
$.ajax({
url: url,
@ -1193,34 +1203,57 @@ function changeToEditMode() {
cancelEditMode();
var self = $(this);
var li = self.closest('li');
var text = li.find('.text');
if ($(text).find('.modal-tooltiptext').length > 0) {
text = $(text).find('.modal-tooltiptext');
var li = $(this).closest('li');
var url = li.attr('data-edit-url');
ajaxCallEvent();
function ajaxCallEvent(){
$.ajax({
url: url,
success: function() {
var text, textEdit, controls, controlsEdit;
text = li.find('.text');
if ($(text).find('.modal-tooltiptext').length > 0) {
text = $(text).find('.modal-tooltiptext');
}
textEdit = li.find('.text-edit');
controls = li.find('.controls .vis,.edit,.del');
controlsEdit = li.find('.controls .ok,.cancel');
// Toggle edit mode
columnEditMode = true;
li.addClass('editing');
// Set the text-edit's value
textEdit.val(text.text().trim());
// Toggle elements
text.hide();
controls.hide();
textEdit.css('display', ''); // show() doesn't work
controlsEdit.css('display', ''); // show() doesn't work
dropdownList.sortable('disable');
dropdownList.on('click', function(ev) {
ev.stopPropagation();
});
// Focus input
textEdit.focus();
},
error: function(e) {
$(li).clearFormErrors();
var msg = $.parseJSON(e.responseText);
renderFormError(undefined,
$(li).find('.text-edit'),
Object.keys(msg)[0] + ' ' + msg.name.toString());
var verticalHeight = $(li).offset().top;
dropdownList.scrollTo(verticalHeight,0);
setTimeout(function() {
$(li).clearFormErrors();
}, 5000);
}
});
}
var textEdit = li.find('.text-edit');
var controls = li.find('.controls .vis,.edit,.del');
var controlsEdit = li.find('.controls .ok,.cancel');
// Toggle edit mode
columnEditMode = true;
li.addClass('editing');
// Set the text-edit's value
textEdit.val(text.text().trim());
// Toggle elements
text.hide();
controls.hide();
textEdit.css('display', ''); // show() doesn't work
controlsEdit.css('display', ''); // show() doesn't work
dropdownList.sortable('disable');
dropdownList.on('click', function(ev) {
ev.stopPropagation();
});
// Focus input
textEdit.focus();
});
// On hiding dropdown, cancel edit mode throughout dropdown

View file

@ -70,6 +70,17 @@
});
clearModal('#modal-delete');
},
error: function (e) {
$(li).clearFormErrors();
var msg = $.parseJSON(e.responseText);
renderFormError(undefined,
$(li).find('.text-edit'),
Object.keys(msg)[0] + ' ' + msg.name.toString());
setTimeout(function() {
$(li).clearFormErrors();
}, 5000);
}
});
});
@ -161,6 +172,17 @@
$(this).find('#sample_type_name'),
Object.keys(msg)[0] + ' '+ msg.name.toString());
});
},
error: function (e) {
$(li).clearFormErrors();
var msg = $.parseJSON(e.responseText);
renderFormError(undefined,
$(li).find('.text-edit'),
Object.keys(msg)[0] + ' ' + msg.name.toString());
setTimeout(function() {
$(li).clearFormErrors();
}, 5000);
}
});
});
@ -202,6 +224,40 @@
$(this).find('#sample_group_name'),
Object.keys(msg)[0] + ' '+ msg.name.toString());
});
},
error: function (e) {
$(li).clearFormErrors();
var msg = $.parseJSON(e.responseText);
renderFormError(undefined,
$(li).find('.text-edit'),
Object.keys(msg)[0] + ' ' + msg.name.toString());
setTimeout(function() {
$(li).clearFormErrors();
}, 5000);
}
});
});
}
function editSampleGroupColor() {
$('.color-picker').on('click', function() {
var li = $(this).closest('li');
$.ajax({
url: li.attr('data-edit'),
success: function(data) {
},
error: function (e) {
$('.dropdown-colorselector.open').removeClass('open');
$(li).clearFormErrors();
var msg = $.parseJSON(e.responseText);
renderFormError(undefined,
$(li).find('.text-edit'),
Object.keys(msg)[0] + ' ' + msg.name.toString());
setTimeout(function() {
$(li).clearFormErrors();
}, 5000);
}
});
});
@ -269,6 +325,7 @@
bindNewSampleGroupAction();
appendCarretToColorPickerDropdown();
sampleTypeGroupEditMode();
editSampleGroupColor();
}
// initialize sample types/groups actions

View file

@ -53,32 +53,6 @@ function updateSamplesTypesandGroups() {
});
}
function sampleAlertMsg(message, type) {
var alertType;
var glyphSign;
$('#notifications').html('');
if (type === 'success') {
alertType = ' alert-success ';
glyphSign = ' glyphicon-ok-sign ';
} else if (type === 'danger') {
alertType = ' alert-danger ';
glyphSign = ' glyphicon-exclamation-sign ';
}
var htmlSnippet = '<div class="alert alert' + alertType +
'alert-dismissable alert-floating">' +
'<div class="container">' +
'<button type="button" class="close" ' +
'data-dismiss="alert" aria-label="Close">' +
'<span aria-hidden="true">×</span></button>' +
'<span class="glyphicon' + glyphSign + '"></span>' +
'<span>' + message + '</span>' +
'</div>' +
'</div>';
$('#notifications').html(htmlSnippet);
$('#content-wrapper').addClass('alert-shown');
HelperModule.hideFlashMsg();
}
/**
* Initializes tutorial
*/

View file

@ -0,0 +1,169 @@
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
modules = (params[:modules].select { |_, p| p == '1' })
.keys
.collect(&:to_i)
# Get unique experiments from given modules
experiments = MyModule.where(id: modules).map(&:experiment).uniq
experiments.each do |experiment|
res << generate_new_el(false)
el = generate_el(
'reports/elements/experiment_element.html.erb',
experiment: experiment
)
el[:children] = generate_experiment_contents_json(experiment, modules)
res << el
end
end
res << generate_new_el(false)
res
end
def generate_experiment_contents_json(experiment, selected_modules)
res = []
experiment.my_modules.each do |my_module|
next unless selected_modules.include?(my_module.id)
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|
protocol = contents.element == :step ? my_module.protocol.present? : true
next unless in_params?("module_#{contents.element}".to_sym) && protocol
res << generate_new_el(false)
if contents.children
contents.collection(my_module).each do |report_el|
el = generate_el(
"reports/elements/my_module_#{contents
.element
.to_s
.singularize}_element.html.erb",
contents.parse_locals([report_el])
)
if contents.element == :step
el[:children] = generate_step_contents_json(report_el)
elsif contents.element == :result
el[:children] = generate_result_contents_json(report_el)
end
res << el
end
else
file_name = contents.file_name
file_name = contents.element if contents.element == :samples
res << generate_el(
"reports/elements/my_module_#{file_name}_element.html.erb",
contents.parse_locals([my_module, :asc])
)
end
end
res << generate_new_el(false)
res
end
def generate_step_contents_json(step)
res = []
if in_params? :step_checklists
step.checklists.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
step.assets.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 == 0
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

@ -1,7 +1,7 @@
class CustomFieldsController < ApplicationController
include InputSanitizeHelper
before_action :load_vars, only: [:update, :destroy, :destroy_html]
before_action :load_vars, except: :create
before_action :load_vars_nested, only: [:create, :destroy_html]
before_action :check_create_permissions, only: :create
before_action :check_update_permissions, only: :update
@ -19,6 +19,8 @@ class CustomFieldsController < ApplicationController
id: @custom_field.id,
name: escape_input(@custom_field.name),
edit_url:
edit_team_custom_field_path(@team, @custom_field),
update_url:
team_custom_field_path(@team, @custom_field),
destroy_html_url:
team_custom_field_destroy_html_path(
@ -36,6 +38,14 @@ class CustomFieldsController < ApplicationController
end
end
def edit
respond_to do |format|
format.json do
render json: { status: :ok }
end
end
end
def update
respond_to do |format|
format.json do

View file

@ -521,7 +521,9 @@ class ProtocolsController < ApplicationController
transaction_error = false
Protocol.transaction do
begin
import_into_existing(@protocol, @protocol_json, current_user)
import_into_existing(
@protocol, @protocol_json, current_user, current_team
)
rescue Exception
transaction_error = true
raise ActiveRecord:: Rollback

View file

@ -1,8 +1,9 @@
class ReportsController < ApplicationController
include TeamsHelper
include ReportActions
# Ignore CSRF protection just for PDF generation (because it's
# used via target='_blank')
protect_from_forgery with: :exception, :except => :generate
protect_from_forgery with: :exception, except: :generate
before_action :load_vars, only: [
:edit,
@ -28,7 +29,7 @@ class ReportsController < ApplicationController
:result_contents
]
before_action :check_view_permissions, only: [:index]
before_action :check_view_permissions, only: :index
before_action :check_create_permissions, only: [
:new,
:create,
@ -46,9 +47,9 @@ class ReportsController < ApplicationController
:step_contents,
:result_contents
]
before_action :check_destroy_permissions, only: [:destroy]
before_action :check_destroy_permissions, only: :destroy
layout "fluid"
layout 'fluid'
# Index showing all reports of a single project
def index
@ -73,7 +74,7 @@ class ReportsController < ApplicationController
@report.user = current_user
@report.last_modified_by = current_user
if continue and @report.save_with_contents(report_contents)
if continue && @report.save_with_contents(report_contents)
# record an activity
Activity.create(
type_of: :create_report,
@ -86,15 +87,15 @@ class ReportsController < ApplicationController
)
)
respond_to do |format|
format.json {
format.json do
render json: { url: project_reports_path(@project) }, status: :ok
}
end
end
else
respond_to do |format|
format.json {
format.json do
render json: @report.errors, status: :unprocessable_entity
}
end
end
end
end
@ -118,7 +119,7 @@ class ReportsController < ApplicationController
@report.last_modified_by = current_user
@report.assign_attributes(report_params)
if continue and @report.save_with_contents(report_contents)
if continue && @report.save_with_contents(report_contents)
# record an activity
Activity.create(
type_of: :edit_report,
@ -131,25 +132,21 @@ class ReportsController < ApplicationController
)
)
respond_to do |format|
format.json {
format.json do
render json: { url: project_reports_path(@project) }, status: :ok
}
end
end
else
respond_to do |format|
format.json {
format.json do
render json: @report.errors, status: :unprocessable_entity
}
end
end
end
end
# Destroy multiple entries action
def destroy
unless params.include? :report_ids
render_404
end
begin
report_ids = JSON.parse(params[:report_ids])
rescue
@ -158,21 +155,19 @@ class ReportsController < ApplicationController
report_ids.each do |report_id|
report = Report.find_by_id(report_id)
if report.present?
# record an activity
Activity.create(
type_of: :delete_report,
project: report.project,
user: current_user,
message: I18n.t(
'activities.delete_report',
user: current_user.full_name,
report: report.name
)
next unless report.present?
# record an activity
Activity.create(
type_of: :delete_report,
project: report.project,
user: current_user,
message: I18n.t(
'activities.delete_report',
user: current_user.full_name,
report: report.name
)
report.destroy
end
)
report.destroy
end
redirect_to project_reports_path(@project)
@ -182,15 +177,13 @@ class ReportsController < ApplicationController
# Currently, only .PDF is supported
def generate
respond_to do |format|
format.pdf {
format.pdf do
@html = params[:html]
if @html.blank? then
@html = "<h1>No content</h1>"
end
render pdf: "report",
@html = '<h1>No content</h1>' if @html.blank?
render pdf: 'report',
header: { right: '[page] of [topage]' },
template: "reports/report.pdf.erb"
}
template: 'reports/report.pdf.erb'
end
end
end
@ -209,33 +202,32 @@ class ReportsController < ApplicationController
@url = project_report_path(@project, @report, format: :json)
end
if !params.include? :contents
render_403 and return
end
render_403 and return unless params.include? :contents
@report_contents = params[:contents]
respond_to do |format|
format.json {
format.json do
render json: {
html: render_to_string({
partial: "reports/new/modal/save.html.erb"
})
html: render_to_string(
partial: 'reports/new/modal/save.html.erb'
)
}
}
end
end
end
# Modal for adding contents into project element
def project_contents_modal
respond_to do |format|
format.json {
format.json do
render json: {
html: render_to_string({
partial: "reports/new/modal/project_contents.html.erb",
html: render_to_string(
partial: 'reports/new/modal/project_contents.html.erb',
locals: { project: @project }
})
)
}
}
end
end
end
@ -274,7 +266,7 @@ class ReportsController < ApplicationController
format.json do
render json: {
html: render_to_string(
partial: "reports/new/modal/module_contents.html.erb",
partial: 'reports/new/modal/module_contents.html.erb',
locals: { project: @project, my_module: my_module }
)
}
@ -289,18 +281,18 @@ class ReportsController < ApplicationController
respond_to do |format|
if step.blank?
format.json {
format.json do
render json: {}, status: :not_found
}
end
else
format.json {
format.json do
render json: {
html: render_to_string({
partial: "reports/new/modal/step_contents.html.erb",
html: render_to_string(
partial: 'reports/new/modal/step_contents.html.erb',
locals: { project: @project, step: step }
})
)
}
}
end
end
end
end
@ -311,18 +303,18 @@ class ReportsController < ApplicationController
respond_to do |format|
if result.blank?
format.json {
format.json do
render json: {}, status: :not_found
}
end
else
format.json {
format.json do
render json: {
html: render_to_string({
partial: "reports/new/modal/result_contents.html.erb",
html: render_to_string(
partial: 'reports/new/modal/result_contents.html.erb',
locals: { project: @project, result: result }
})
)
}
}
end
end
end
end
@ -384,12 +376,12 @@ class ReportsController < ApplicationController
if elements_empty? elements
format.json { render json: {}, status: :no_content }
else
format.json {
format.json do
render json: {
status: :ok,
elements: elements
}
}
end
end
end
end
@ -442,242 +434,31 @@ class ReportsController < ApplicationController
private
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
modules = (params[:modules].select { |_, p| p == '1' })
.keys
.collect(&:to_i)
# Get unique experiments from given modules
experiments = MyModule.where(id: modules).map(&:experiment).uniq
experiments.each do |experiment|
res << generate_new_el(false)
el = generate_el(
'reports/elements/experiment_element.html.erb',
experiment: experiment
)
el[:children] = generate_experiment_contents_json(experiment, modules)
res << el
end
end
res << generate_new_el(false)
res
end
def generate_experiment_contents_json(experiment, selected_modules)
res = []
experiment.my_modules.each do |my_module|
next unless selected_modules.include?(my_module.id)
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 = []
if (in_params? :module_steps) && my_module.protocol.present? then
my_module.protocol.completed_steps.each do |step|
res << generate_new_el(false)
el = generate_el(
"reports/elements/step_element.html.erb",
{ step: step }
)
el[:children] = generate_step_contents_json(step)
res << el
end
end
if in_params? :module_result_assets then
(my_module.results.select { |r| r.is_asset && r.active? }).each do |result_asset|
res << generate_new_el(false)
el = generate_el(
"reports/elements/result_asset_element.html.erb",
{ result: result_asset }
)
el[:children] = generate_result_contents_json(result_asset)
res << el
end
end
if in_params? :module_result_tables then
(my_module.results.select { |r| r.is_table && r.active? }).each do |result_table|
res << generate_new_el(false)
el = generate_el(
"reports/elements/result_table_element.html.erb",
{ result: result_table }
)
el[:children] = generate_result_contents_json(result_table)
res << el
end
end
if in_params? :module_result_texts then
(my_module.results.select { |r| r.is_text && r.active? }).each do |result_text|
res << generate_new_el(false)
el = generate_el(
"reports/elements/result_text_element.html.erb",
result: result_text
)
el[:children] = generate_result_contents_json(result_text)
res << el
end
end
if in_params? :module_activity then
res << generate_new_el(false)
res << generate_el(
"reports/elements/my_module_activity_element.html.erb",
{ my_module: my_module, order: :asc }
)
end
if in_params? :module_samples then
res << generate_new_el(false)
res << generate_el(
"reports/elements/my_module_samples_element.html.erb",
{ my_module: my_module, order: :asc }
)
end
res << generate_new_el(false)
res
end
def generate_step_contents_json(step)
res = []
if in_params? :step_checklists then
step.checklists.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 then
step.assets.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 then
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 then
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 then
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)
if elements.blank?
return true
elsif elements.count == 0 then
return true
elsif elements.count == 1
el = elements[0]
if el.include? :new_element and el[:new_element]
return true
else
return false
end
end
return false
end
def load_vars
@report = Report.find_by_id(params[:id])
unless @report
render_404
end
render_404 unless @report
end
def load_vars_nested
@project = Project.find_by_id(params[:project_id])
unless @project
render_404
end
render_404 unless @project
end
def check_view_permissions
unless can_view_reports(@project)
render_403
end
render_403 unless can_view_reports(@project)
end
def check_create_permissions
unless can_create_new_report(@project)
render_403
end
render_403 unless can_create_new_report(@project)
end
def check_destroy_permissions
unless can_delete_reports(@project)
render_403
end
render_403 unless can_delete_reports(@project)
render_404 unless params.include? :report_ids
end
def report_params
params.require(:report).permit(:name, :description, :grouped_by, :report_contents)
params.require(:report)
.permit(:name, :description, :grouped_by, :report_contents)
end
end

View file

@ -29,6 +29,7 @@ class ResultAssetsController < ApplicationController
@asset = Asset.new(result_params[:asset_attributes])
@asset.created_by = current_user
@asset.last_modified_by = current_user
@asset.team = current_team
@result = Result.new(
user: current_user,
my_module: @my_module,
@ -98,6 +99,7 @@ class ResultAssetsController < ApplicationController
asset = Asset.find_by_id(update_params[:asset_attributes][:id])
asset.created_by = current_user
asset.last_modified_by = current_user
asset.team = current_team
@result.asset = asset
end

View file

@ -31,6 +31,7 @@ class ResultTablesController < ApplicationController
def create
@table = Table.new(result_params[:table_attributes])
@table.created_by = current_user
@table.team = current_team
@table.last_modified_by = current_user
@result = Result.new(
user: current_user,
@ -92,6 +93,7 @@ class ResultTablesController < ApplicationController
update_params = result_params
@result.last_modified_by = current_user
@result.table.last_modified_by = current_user
@result.table.team = current_team
@result.assign_attributes(update_params)
flash_success = t("result_tables.update.success_flash",
module: @my_module.name)
@ -218,6 +220,4 @@ class ResultTablesController < ApplicationController
]
)
end
end

View file

@ -33,6 +33,14 @@ class StepsController < ApplicationController
@step.protocol = @protocol
@step.user = current_user
@step.last_modified_by = current_user
@step.assets.each do |asset|
asset.created_by = current_user
asset.team = current_team
end
@step.tables.each do |table|
table.created_by = current_user
table.team = current_team
end
# Update default checked state
@step.checklists.each do |checklist|
@ -133,6 +141,18 @@ class StepsController < ApplicationController
@step.assign_attributes(step_params_all)
@step.last_modified_by = current_user
@step.assets.each do |asset|
asset.created_by = current_user if asset.new_record?
asset.last_modified_by = current_user unless asset.new_record?
asset.team = current_team
end
@step.tables.each do |table|
table.created_by = current_user if table.new_record?
table.last_modified_by = current_user unless table.new_record?
table.team = current_team
end
if @step.save
@step.reload

View file

@ -1,99 +1,95 @@
module ReportsHelper
def render_new_element(hide)
render partial: 'reports/elements/new_element.html.erb',
locals: { hide: hide }
end
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)
children_html = ''.html_safe
def render_report_element(element, provided_locals = nil)
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.has_children?
children_html.safe_concat render_new_element(true)
element.children.each do |child|
children_html.safe_concat render_report_element(child, provided_locals)
# 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.has_children?
children_html.safe_concat render_new_element(true)
element.children.each do |child|
children_html
.safe_concat render_report_element(child, provided_locals)
end
else
children_html.safe_concat render_new_element(false)
end
else
if element.has_children?
element.children.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
else
if element.has_children?
element.children.each do |child|
children_html.safe_concat render_new_element(false)
children_html.safe_concat render_report_element(child, provided_locals)
end
file_name = element.type_of
if element.type_of.in? %w(step result_asset result_table result_text)
file_name = "my_module_#{element.type_of.singularize}"
end
children_html.safe_concat render_new_element(false)
view = "reports/elements/#{file_name}_element.html.erb"
locals = provided_locals.nil? ? {} : provided_locals.clone
locals[:children] = children_html
# ReportExtends is located in config/initializers/extends/report_extends.rb
ReportElement.type_ofs.keys.each do |type|
next unless element.public_send("#{type}?")
local_sym = type.split('_').last.to_sym
local_sym = type
.split('_')
.first
.to_sym if type.in? ReportExtends::FIRST_PART_ELEMENTS
local_sym = :my_module if type.in? ReportExtends::MY_MODULE_ELEMENTS
locals[local_sym] = element.element_reference
locals[:order] = element
.sort_order if type.in? ReportExtends::SORTED_ELEMENTS
end
(render partial: view, locals: locals).html_safe
end
view = "reports/elements/#{element.type_of}_element.html.erb"
locals = provided_locals.nil? ? {} : provided_locals.clone
locals[:children] = children_html
if element.project_header?
locals[:project] = element.element_reference
elsif element.experiment?
locals[:experiment] = element.element_reference
elsif element.my_module?
locals[:my_module] = element.element_reference
elsif element.step?
locals[:step] = element.element_reference
elsif element.result_asset?
locals[:result] = element.element_reference
elsif element.result_table?
locals[:result] = element.element_reference
elsif element.result_text?
locals[:result] = element.element_reference
elsif element.my_module_activity?
locals[:my_module] = element.element_reference
locals[:order] = element.sort_order
elsif element.my_module_samples?
locals[:my_module] = element.element_reference
locals[:order] = element.sort_order
elsif element.step_checklist?
locals[:checklist] = element.element_reference
elsif element.step_asset?
locals[:asset] = element.element_reference
elsif element.step_table?
locals[:table] = element.element_reference
elsif element.step_comments?
locals[:step] = element.element_reference
locals[:order] = element.sort_order
elsif element.result_comments?
locals[:result] = element.element_reference
locals[:order] = element.sort_order
elsif element.project_activity?
# TODO
elsif element.project_samples?
# TODO
# "Hack" to omit file preview URL because of WKHTML issues
def report_image_asset_url(asset)
prefix = ''
if ENV['PAPERCLIP_STORAGE'].present? &&
ENV['MAIL_SERVER_URL'].present? &&
ENV['PAPERCLIP_STORAGE'] == 'filesystem'
prefix = ENV['MAIL_SERVER_URL']
end
if !prefix.empty? &&
!prefix.include?('http://') &&
!prefix.include?('https://')
prefix = "http://#{prefix}"
end
url = prefix + asset.url(:medium, timeout: Constants::URL_LONG_EXPIRE_TIME)
image_tag(url)
end
return (render partial: view, locals: locals).html_safe
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
# "Hack" to omit file preview URL because of WKHTML issues
def report_image_asset_url(asset)
prefix = (ENV["PAPERCLIP_STORAGE"].present? && ENV["MAIL_SERVER_URL"].present? && ENV["PAPERCLIP_STORAGE"] == "filesystem") ? ENV["MAIL_SERVER_URL"] : ""
prefix = (!prefix.empty? && !prefix.include?("http://") && !prefix.include?("https://")) ? "http://#{prefix}" : prefix
url = prefix + asset.url(:medium, timeout: Constants::URL_LONG_EXPIRE_TIME)
image_tag(url)
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"]
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://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css'
)
end
def font_awesome_cdn_link_tag
stylesheet_link_tag(
'https://maxcdn.bootstrapcdn.com/font-awesome' \
'/4.6.3/css/font-awesome.min.css'
)
end
end

View file

@ -48,6 +48,7 @@ class Asset < ActiveRecord::Base
belongs_to :last_modified_by,
foreign_key: 'last_modified_by_id',
class_name: 'User'
belongs_to :team
has_one :step_asset,
inverse_of: :asset,
dependent: :destroy

View file

@ -291,8 +291,6 @@ class Protocol < ActiveRecord::Base
)
item2.created_by = current_user
item2.last_modified_by = current_user
p item
p item2
item2.save
end
@ -306,6 +304,7 @@ class Protocol < ActiveRecord::Base
asset.file_file_size
)
asset2.created_by = current_user
asset2.team = dest.team
asset2.last_modified_by = current_user
asset2.file_processing = true if asset.is_image?
asset2.save
@ -323,6 +322,7 @@ class Protocol < ActiveRecord::Base
table2 = Table.new(name: table.name, contents: table.contents)
table2.created_by = current_user
table2.last_modified_by = current_user
table2.team = dest.team
step2.tables << table2
end
end

View file

@ -105,12 +105,13 @@ class Report < ActiveRecord::Base
el.position = index
el.report = self
el.parent = parent
el.type_of = json_element["type_of"]
el.sort_order = json_element["sort_order"]
el.set_element_reference(json_element["id"])
el.type_of = json_element['type_of']
el.sort_order = json_element['sort_order']
el.set_element_reference(json_element['id'])
el.save!
if json_element["children"].present?
json_element["children"].each_with_index do |child, i|
if json_element['children'].present?
json_element['children'].each_with_index do |child, i|
save_json_element(child, i, el)
end
end

View file

@ -1,22 +1,5 @@
class ReportElement < ActiveRecord::Base
enum type_of: {
project_header: 0,
my_module: 1,
step: 2,
result_asset: 3,
result_table: 4,
result_text: 5,
my_module_activity: 6,
my_module_samples: 7,
step_checklist: 8,
step_asset: 9,
step_table: 10,
step_comments: 11,
result_comments: 12,
project_activity: 13, # TODO
project_samples: 14, # TODO
experiment: 15
}
enum type_of: Extends::REPORT_ELEMENT_TYPES
# This is only used by certain elements
enum sort_order: {
@ -32,8 +15,12 @@ class ReportElement < ActiveRecord::Base
belongs_to :report, inverse_of: :report_elements
# Hierarchical structure representation
has_many :children, -> { order(:position) }, class_name: "ReportElement", foreign_key: "parent_id", dependent: :destroy
belongs_to :parent, class_name: "ReportElement"
has_many :children,
-> { order(:position) },
class_name: 'ReportElement',
foreign_key: 'parent_id',
dependent: :destroy
belongs_to :parent, class_name: 'ReportElement'
# References to various report entities
belongs_to :project, inverse_of: :report_elements
@ -59,44 +46,18 @@ class ReportElement < ActiveRecord::Base
# Get the referenced element (previously, element's type_of must be set)
def element_reference
if project_header? or project_activity? or project_samples?
return project
elsif experiment?
return experiment
elsif my_module? or my_module_activity? or my_module_samples?
return my_module
elsif step? or step_comments?
return step
elsif result_asset? or result_table? or result_text? or result_comments?
return result
elsif step_checklist?
return checklist
elsif step_asset?
return asset
elsif step_table?
return table
ReportExtends::ELEMENT_REFERENCES.each do |el_ref|
return eval(el_ref.element.gsub('_id', '')) if el_ref.check(self)
end
end
# Set the element reference (previously, element's type_of must be set)
def set_element_reference(ref_id)
if project_header? or project_activity? or project_samples?
self.project_id = ref_id
elsif experiment?
self.experiment_id = ref_id
elsif my_module? or my_module_activity? or my_module_samples?
self.my_module_id = ref_id
elsif step? or step_comments?
self.step_id = ref_id
elsif result_asset? or result_table? or result_text? or result_comments?
self.result_id = ref_id
elsif step_checklist?
self.checklist_id = ref_id
elsif step_asset?
self.asset_id = ref_id
elsif step_table?
self.table_id = ref_id
ReportExtends::SET_ELEMENT_REFERENCES_LIST.each do |el_ref|
check = el_ref.check(self)
next unless check
public_send("#{el_ref.element}=", ref_id)
break
end
end
@ -120,18 +81,17 @@ class ReportElement < ActiveRecord::Base
private
def has_one_of_referenced_elements
num_of_refs = [
project,
experiment,
my_module,
step,
result,
checklist,
asset,
table
].count { |r| r.present? }
num_of_refs = [project,
experiment,
my_module,
step,
result,
checklist,
asset,
table].count { |r| r.present? }
if num_of_refs != 1
errors.add(:base, "Report element must have exactly one element reference.")
errors.add(:base,
'Report element must have exactly one element reference.')
end
end
end

View file

@ -10,6 +10,7 @@ class Table < ActiveRecord::Base
belongs_to :created_by, foreign_key: 'created_by_id', class_name: 'User'
belongs_to :last_modified_by, foreign_key: 'last_modified_by_id', class_name: 'User'
belongs_to :team
has_one :step_table, inverse_of: :table
has_one :step, through: :step_table

View file

@ -1,11 +1,12 @@
module DelayedUploaderTutorial
# Get asset from tutorial_files folder
def self.get_asset(user, file_name)
def self.get_asset(user, team, file_name)
Asset.new(
file: File.open(
"#{Rails.root}/app/assets/tutorial_files/#{file_name}", 'r'
),
created_by: user,
team: team,
last_modified_by: user
)
end
@ -15,11 +16,12 @@ module DelayedUploaderTutorial
def self.generate_result_asset(
my_module:,
current_user:,
current_team:,
result_name:,
created_at: Time.now,
file_name:
)
temp_asset = get_asset(current_user, file_name)
temp_asset = get_asset(current_user, current_team, file_name)
temp_result = Result.new(
created_at: created_at,
user: current_user,
@ -48,8 +50,9 @@ module DelayedUploaderTutorial
end
# Adds asset to existing step
def self.add_step_asset(step:, current_user:, file_name:)
temp_asset = DelayedUploaderTutorial.get_asset(current_user, file_name)
def self.add_step_asset(step:, current_user:, current_team:, file_name:)
temp_asset =
DelayedUploaderTutorial.get_asset(current_user, current_team, file_name)
step.assets << temp_asset
temp_asset.post_process_file(step.my_module.experiment.project.team)
end

View file

@ -422,6 +422,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[0],
current_user: user,
current_team: team,
result_name: 'sF',
created_at: generate_random_time(my_modules[0].created_at, 2.days),
file_name: 'samples.txt'
@ -440,6 +441,7 @@ module FirstTimeDataGenerator
)
temp_result.table = Table.new(
created_by: user,
team: team,
contents: tab_content['module1']['experimental_design']
)
temp_result.save
@ -467,6 +469,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[1].protocol.steps.where('position = 0').take,
current_user: user,
current_team: team,
file_name: 'sample-potatoe.txt'
)
@ -474,6 +477,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[1],
current_user: user,
current_team: team,
result_name: 'PVY-inoculated plant, symptoms',
created_at: generate_random_time(my_modules[1].created_at, 1.days),
file_name: 'DSCN0660.JPG'
@ -482,6 +486,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[1],
current_user: user,
current_team: team,
result_name: 'mock-inoculated plant',
created_at: generate_random_time(my_modules[1].created_at, 2.days),
file_name: 'DSCN0354.JPG'
@ -490,6 +495,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[1],
current_user: user,
current_team: team,
result_name: 'Height of plants at 6dpi',
created_at: generate_random_time(my_modules[1].created_at, 3.days),
file_name: '6dpi_height.JPG'
@ -541,6 +547,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[2].protocol.steps.where('position = 1').take,
current_user: user,
current_team: team,
file_name: 'RNeasy-Plant-Mini-Kit-EN.pdf'
)
@ -559,6 +566,7 @@ module FirstTimeDataGenerator
)
temp_result.table = Table.new(
created_by: user,
team: team,
contents: tab_content['module3']['nanodrop']
)
temp_result.save
@ -581,6 +589,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[2],
current_user: user,
current_team: team,
result_name: 'Agarose gel electrophoresis of totRNA samples',
created_at: generate_random_time(my_modules[2].created_at, 3.days),
file_name: 'totRNA_gel.jpg'
@ -599,6 +608,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[3].protocol.steps.where('position = 0').take,
current_user: user,
current_team: team,
file_name: 'G2938-90034_KitRNA6000Nano_ebook.pdf'
)
@ -606,6 +616,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[3],
current_user: user,
current_team: team,
result_name: 'Result of RNA integrity',
created_at: generate_random_time(my_modules[3].created_at, 2.days),
file_name: 'Bioanalyser_result.JPG'
@ -671,24 +682,28 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[5].protocol.steps.where('position = 0').take,
current_user: user,
current_team: team,
file_name: 'sample_preparation.JPG'
)
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[5].protocol.steps.where('position = 1').take,
current_user: user,
current_team: team,
file_name: 'reaction_setup.JPG'
)
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[5].protocol.steps.where('position = 2').take,
current_user: user,
current_team: team,
file_name: 'cycling_conditions.JPG'
)
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[5].protocol.steps.where('position = 3').take,
current_user: user,
current_team: team,
file_name: '96plate.doc'
)
@ -702,6 +717,7 @@ module FirstTimeDataGenerator
)
temp_result.table = Table.new(
created_by: user,
team: team,
contents: tab_content['module6']['distribution'] % {
sample0: samples_to_assign[0].name,
sample1: samples_to_assign[1].name,
@ -729,6 +745,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[5],
current_user: user,
current_team: team,
result_name: 'Mixtures and plate setup',
created_at: generate_random_time(my_modules[5].created_at, 2.days),
file_name: 'Mixes_Templats.xls'
@ -737,6 +754,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[5],
current_user: user,
current_team: team,
result_name: 'Raw data from ABI 7300',
created_at: generate_random_time(my_modules[5].created_at, 3.days),
file_name: 'BootCamp-Experiment-results-20122.sds'
@ -745,6 +763,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[5],
current_user: user,
current_team: team,
result_name: 'All results - curves',
created_at: generate_random_time(my_modules[5].created_at, 4.days),
file_name: 'curves.JPG'
@ -791,6 +810,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).add_step_asset(
step: my_modules[7].protocol.steps.where('position = 0').take,
current_user: user,
current_team: team,
file_name: 'ddCq-quantification_diagnostics-template.xls'
)
@ -798,6 +818,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[7],
current_user: user,
current_team: team,
result_name: 'Results of ddCq method',
created_at: generate_random_time(my_modules[7].created_at, 1.days),
file_name: 'ddCq-quantification_diagnostics-results.xls'
@ -806,6 +827,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[7],
current_user: user,
current_team: team,
result_name: 'Dilution curve and efficiency',
created_at: generate_random_time(my_modules[7].created_at, 2.days),
file_name: 'dilution_curve-efficiency.JPG'
@ -814,6 +836,7 @@ module FirstTimeDataGenerator
DelayedUploaderTutorial.delay(queue: :tutorial).generate_result_asset(
my_module: my_modules[7],
current_user: user,
current_team: team,
result_name: 'Relative quantification results',
created_at: generate_random_time(my_modules[7].created_at, 3.days),
file_name: 'result-ddCq.JPG'

View file

@ -22,18 +22,18 @@ module ProtocolsImporter
protocol.save!
# Protocol is saved, populate it
populate_protocol(protocol, protocol_json, user)
populate_protocol(protocol, protocol_json, user, team)
return protocol
end
def import_into_existing(protocol, protocol_json, user)
def import_into_existing(protocol, protocol_json, user, team)
# Firstly, destroy existing protocol's contents
protocol.destroy_contents(user)
protocol.reload
# Alright, now populate the protocol
populate_protocol(protocol, protocol_json, user)
populate_protocol(protocol, protocol_json, user, team)
protocol.reload
# Unlink the protocol
@ -43,7 +43,7 @@ module ProtocolsImporter
private
def populate_protocol(protocol, protocol_json, user)
def populate_protocol(protocol, protocol_json, user, team)
protocol.reload
asset_ids = []
@ -93,7 +93,8 @@ module ProtocolsImporter
name: table_json['name'],
contents: Base64.decode64(table_json['contents']),
created_by: user,
last_modified_by: user
last_modified_by: user,
team: team
)
StepTable.create!(
step: step,
@ -106,7 +107,8 @@ module ProtocolsImporter
step_json["assets"].values.each do |asset_json|
asset = Asset.new(
created_by: user,
last_modified_by: user
last_modified_by: user,
team: team
)
# Decode the file bytes

View file

@ -18,4 +18,4 @@
<div class="report-element-children">
<%= children if (defined? children and children.present?) %>
</div>
</div>
</div>

View file

@ -5,15 +5,18 @@
team_sample_group_destroy_confirmation_path(team, sample_group) %>"
data-color="<%= sample_group.color %>">
<span class="sample-type-group-name"><%= sample_group.name %></span>
<span class="pull-right sample-group-controls">
<span class="color-picker">
<%= bootstrap_form_for [team, sample_group], remote: true do |f| %>
<%= f.color_picker_select :color,
Constants::TAG_COLORS,
class: 'edit-sample-group-color' %>
<% end %>
<span class="form-group">
<input class="text-edit" style="display: none;" />
<span class="pull-right sample-group-controls">
<span class="color-picker">
<%= bootstrap_form_for [team, sample_group], remote: true do |f| %>
<%= f.color_picker_select :color,
Constants::TAG_COLORS,
class: 'edit-sample-group-color' %>
<% end %>
</span>
<span class="edit-sample-group glyphicon glyphicon-pencil"></span>
<span class="delete glyphicon glyphicon-trash"></span>
</span>
<span class="edit-sample-group glyphicon glyphicon-pencil"></span>
<span class="delete glyphicon glyphicon-trash"></span>
</span>
</li>

View file

@ -4,8 +4,11 @@
team_sample_type_destroy_confirmation_path(team, sample_type)
%>">
<span class="sample-type-group-name"><%= sample_type.name %></span>
<span class="pull-right">
<span class="edit-sample-type glyphicon glyphicon-pencil"></span>
<span class="delete glyphicon glyphicon-trash"></span>
<span class="form-group">
<input class="text-edit" style="display: none;" />
<span class="pull-right">
<span class="edit-sample-type glyphicon glyphicon-pencil"></span>
<span class="delete glyphicon glyphicon-trash"></span>
</span>
</span>
</li>

View file

@ -86,7 +86,8 @@
</span>
</a>
<ul class="dropdown-menu ">
<ul class="dropdown-menu"
data-hook="teams-dropdown">
<%= form_for(current_user,
url: user_current_team_path,
method: :post) do |f| %>
@ -103,9 +104,11 @@
<% end %>
<% end %>
<% if current_user.teams.length > 1 %>
<li role="separator" class="divider"></li>
<li data-hook="new-team-btn"
role="separator"
class="divider"></li>
<% end %>
<li>
<li data-hook="new-team-btn">
<%= link_to new_team_path do %>
<span class="glyphicon glyphicon-plus"></span>
<%= t('users.settings.teams.index.new_team') %>

View file

@ -145,7 +145,8 @@
id="<%= cf.id %>"
<%= 'data-editable' if can_edit_custom_field(cf) %>
<%= 'data-deletable' if can_delete_custom_field(cf) %>
<%= "data-edit-url='#{team_custom_field_path(@team, cf)}'" %>
<%= "data-edit-url='#{edit_team_custom_field_path(@team, cf)}'" %>
<%= "data-update-url='#{team_custom_field_path(@team, cf)}'" %>
<%= "data-destroy-html-url='#{team_custom_field_destroy_html_path(@team, cf)}'" %>
>
<%= display_tooltip(cf.name) %>

View file

@ -190,7 +190,7 @@ class Constants
#=============================================================================
# Application version
APP_VERSION = '1.8.1'.freeze
APP_VERSION = '1.9.0'.freeze
TEXT_EXTRACT_FILE_TYPES = [
'application/pdf',

View file

@ -10,7 +10,7 @@ class Extends
# > end
# >
# Notification types. Should not be freezed, as modules might append to this.
# Extends enum types. Should not be freezed, as modules might append to this.
# !!!Check all addons for the correct order!!!
NOTIFICATIONS_TYPES = { assignment: 0,
recent_changes: 1,
@ -19,4 +19,22 @@ class Extends
TASKS_STATES = { uncompleted: 0,
completed: 1 }
REPORT_ELEMENT_TYPES = { project_header: 0,
my_module: 1,
step: 2,
result_asset: 3,
result_table: 4,
result_text: 5,
my_module_activity: 6,
my_module_samples: 7,
step_checklist: 8,
step_asset: 9,
step_table: 10,
step_comments: 11,
result_comments: 12,
project_activity: 13, # TODO
project_samples: 14, # TODO
experiment: 15 }
end

View file

@ -0,0 +1,195 @@
#########################################################
# 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.
# :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 prock which the my_module is passed and have to return a
# collection of element
# :singular => true by defaut change the enum type to singular
# needed when querying partials by name
ModuleElement = Struct.new(:element,
:children,
:locals,
:coll,
:singular) do
def initialize(element, children, locals, coll = nil, singular = true)
super(element, children, locals, coll, singular)
end
def collection(my_module)
coll.call(my_module) 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
# Module contents element
MODULE_CONTENTS = [
ModuleElement.new(:steps,
true,
[:step],
proc do |my_module|
my_module.protocol.completed_steps
end),
ModuleElement.new(:result_assets,
true,
[:result],
proc do |my_module|
my_module.results.select { |r| r.is_asset && r.active? }
end),
ModuleElement.new(:result_tables,
true,
[:result],
proc do |my_module|
my_module.results.select { |r| r.is_table && r.active? }
end),
ModuleElement.new(:result_texts,
true,
[:result],
proc do |my_module|
my_module.results.select { |r| r.is_text && r.active? }
end),
ModuleElement.new(:activity,
false,
[:my_module, :order]),
ModuleElement.new(:samples,
false,
[:my_module, :order])
]
# path: app/helpers/reports_helpers.rb
# method: render_report_element
# adds :order local to listed elements views
# ADD REPORT ELEMENT TYPE WHICH YOU WANT TO PASS 'ORDER' LOCAL IN THE PARTIAL
SORTED_ELEMENTS = %w(my_module_activity
my_module_samples
step_comments
result_comments)
# sets local :my_module to the listed my_module child elements
MY_MODULE_ELEMENTS = %w(my_module my_module_activity my_module_samples)
# 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)
# path: app/models/report_element.rb
# method: set_element_reference
ElementReference = Struct.new(:checker, :element) do
def initialize(checker, element = :element_reference_needed!)
super(checker, element)
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? ||
report_element.project_activity? ||
report_element.project_samples?
end,
'project_id'
),
ElementReference.new(proc(&:experiment?), 'experiment_id'),
ElementReference.new(
proc do |report_element|
report_element.my_module? ||
report_element.my_module_activity? ||
report_element.my_module_samples?
end,
'my_module_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? ||
report_element.project_activity? ||
report_element.project_samples?
end,
'project_id'
),
ElementReference.new(proc(&:experiment?), 'experiment_id'),
ElementReference.new(
proc do |report_element|
report_element.my_module? ||
report_element.my_module_activity? ||
report_element.my_module_samples?
end,
'my_module_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

@ -1040,6 +1040,12 @@ en:
start_edit_wopi_file_result: "<i>%{user}</i> started editing File %{file} on Result <strong>%{result}</strong>."
unlock_wopi_file_step: "<i>%{user}</i> closed File %{file} for editing on Step %{step} <strong>%{step_name}</strong>."
unlock_wopi_file_result: "<i>%{user}</i> started editing File %{file} on Result <strong>%{result}</strong>."
load_protocol_from_file: "<i>%{user}</i> loaded protocol <strong>%{protocol}</strong> from file."
load_protocol_from_repository: "<i>%{user}</i> loaded protocol <strong>%{protocol}</strong> from repository."
revert_protocol: "<i>%{user}</i> reverted protocol <strong>%{protocol}</strong> from repository."
create_report: "<i>%{user}</i> created report <strong>%{report}</strong>."
delete_report: "<i>%{user}</i> deleted report <strong>%{report}</strong>."
edit_report: "<i>%{user}</i> edited report <strong>%{report}</strong>."
user_my_modules:
new:
@ -1071,14 +1077,6 @@ en:
create: "Add comment"
create:
success_flash: "Successfully added comment to result."
load_protocol_from_file: "<i>%{user}</i> loaded protocol <strong>%{protocol}</strong> from file."
load_protocol_from_repository: "<i>%{user}</i> loaded protocol <strong>%{protocol}</strong> from repository."
revert_protocol: "<i>%{user}</i> reverted protocol <strong>%{protocol}</strong> from repository."
create_report: "<i>%{user}</i> created report <strong>%{report}</strong>."
delete_report: "<i>%{user}</i> deleted report <strong>%{report}</strong>."
edit_report: "<i>%{user}</i> edited report <strong>%{report}</strong>."
assign_sample: "<i>%{user}</i> assigned sample(s) <strong>%{samples}</strong> to task(s) <strong>%{tasks}</strong>."
unassign_sample: "<i>%{user}</i> unassigned sample(s) <strong>%{samples}</strong> from task(s) <strong>%{tasks}</strong>."
users:
enums:

View file

@ -132,7 +132,7 @@ Rails.application.routes.draw do
get 'sample_group_element', to: 'sample_groups#sample_group_element'
get 'destroy_confirmation', to: 'sample_groups#destroy_confirmation'
end
resources :custom_fields, only: [:create, :update, :destroy] do
resources :custom_fields, only: [:create, :edit, :update, :destroy] do
get 'destroy_html'
end
member do

View file

@ -0,0 +1,29 @@
class AddTeamIdToAssetAndTables < ActiveRecord::Migration
def change
add_column :assets, :team_id, :integer
add_index :assets, :team_id
add_column :tables, :team_id, :integer
add_index :tables, :team_id
Asset.find_each do |asset|
if asset.result
asset.update_columns(
team_id: asset.result.my_module.experiment.project.team_id
)
elsif asset.step
asset.update_columns(team_id: asset.step.protocol.team_id)
end
end
Table.find_each do |table|
if table.result
table.update_columns(
team_id: table.result.my_module.experiment.project.team_id
)
elsif table.step
table.update_columns(team_id: table.step.protocol.team_id)
end
end
end
end