mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-21 07:26:15 +08:00
Merge branch 'master' into features/note-section
This commit is contained in:
commit
645930b8d7
2
Gemfile
2
Gemfile
|
@ -11,7 +11,7 @@ gem 'devise_invitable'
|
|||
gem 'figaro'
|
||||
gem 'pg', '~> 0.18'
|
||||
gem 'pg_search' # PostgreSQL full text search
|
||||
gem 'rails', '5.1.6'
|
||||
gem 'rails', '~> 5.1.6.2'
|
||||
gem 'recaptcha', require: 'recaptcha/rails'
|
||||
gem 'sanitize', '~> 4.4'
|
||||
gem 'sass-rails', '~> 5.0.6'
|
||||
|
|
68
Gemfile.lock
68
Gemfile.lock
|
@ -51,25 +51,25 @@ GIT
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
actioncable (5.1.6)
|
||||
actionpack (= 5.1.6)
|
||||
actioncable (5.1.6.2)
|
||||
actionpack (= 5.1.6.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (~> 0.6.1)
|
||||
actionmailer (5.1.6)
|
||||
actionpack (= 5.1.6)
|
||||
actionview (= 5.1.6)
|
||||
activejob (= 5.1.6)
|
||||
actionmailer (5.1.6.2)
|
||||
actionpack (= 5.1.6.2)
|
||||
actionview (= 5.1.6.2)
|
||||
activejob (= 5.1.6.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (5.1.6)
|
||||
actionview (= 5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
actionpack (5.1.6.2)
|
||||
actionview (= 5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
rack (~> 2.0)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
actionview (5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
|
@ -79,18 +79,18 @@ GEM
|
|||
activemodel (>= 4.1, < 6)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
activejob (5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
activejob (5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
activerecord (5.1.6)
|
||||
activemodel (= 5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
activemodel (5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
activerecord (5.1.6.2)
|
||||
activemodel (= 5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
arel (~> 8.0)
|
||||
activerecord-import (0.23.0)
|
||||
activerecord (>= 3.2)
|
||||
activesupport (5.1.6)
|
||||
activesupport (5.1.6.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
@ -383,17 +383,17 @@ GEM
|
|||
rack (>= 1.0, < 3)
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (5.1.6)
|
||||
actioncable (= 5.1.6)
|
||||
actionmailer (= 5.1.6)
|
||||
actionpack (= 5.1.6)
|
||||
actionview (= 5.1.6)
|
||||
activejob (= 5.1.6)
|
||||
activemodel (= 5.1.6)
|
||||
activerecord (= 5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
rails (5.1.6.2)
|
||||
actioncable (= 5.1.6.2)
|
||||
actionmailer (= 5.1.6.2)
|
||||
actionpack (= 5.1.6.2)
|
||||
actionview (= 5.1.6.2)
|
||||
activejob (= 5.1.6.2)
|
||||
activemodel (= 5.1.6.2)
|
||||
activerecord (= 5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 5.1.6)
|
||||
railties (= 5.1.6.2)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.2)
|
||||
actionpack (~> 5.x, >= 5.0.1)
|
||||
|
@ -411,14 +411,14 @@ GEM
|
|||
rails (> 3.1)
|
||||
rails_serve_static_assets (0.0.5)
|
||||
rails_stdout_logging (0.0.5)
|
||||
railties (5.1.6)
|
||||
actionpack (= 5.1.6)
|
||||
activesupport (= 5.1.6)
|
||||
railties (5.1.6.2)
|
||||
actionpack (= 5.1.6.2)
|
||||
activesupport (= 5.1.6.2)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
rake (12.3.1)
|
||||
rake (12.3.2)
|
||||
rb-fsevent (0.10.2)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
|
@ -631,7 +631,7 @@ DEPENDENCIES
|
|||
pry-rails
|
||||
puma
|
||||
rack-attack
|
||||
rails (= 5.1.6)
|
||||
rails (~> 5.1.6.2)
|
||||
rails-controller-testing
|
||||
rails_12factor
|
||||
rails_autolink (~> 1.1, >= 1.1.6)
|
||||
|
|
|
@ -119,27 +119,25 @@
|
|||
});
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
// Bind modal to new-experiment action
|
||||
initializeModal($('#new-experiment'), '#new-experiment-modal');
|
||||
// Bind modal to new-experiment action
|
||||
initializeModal($('#new-experiment'), '#new-experiment-modal');
|
||||
|
||||
// Bind modal to big-plus new experiment actions
|
||||
initializeModal('.big-plus', '#new-experiment-modal');
|
||||
// Bind modal to big-plus new experiment actions
|
||||
initializeModal('.big-plus', '#new-experiment-modal');
|
||||
|
||||
// Bind modal to new-exp-title action
|
||||
initializeModal('.new-exp-title', '#new-experiment-modal');
|
||||
// Bind modal to new-exp-title action
|
||||
initializeModal('.new-exp-title', '#new-experiment-modal');
|
||||
|
||||
// Bind modals to all clone-experiment actions
|
||||
$.each($('.clone-experiment'), function() {
|
||||
var id = $(this).closest('.experiment-panel').data('id');
|
||||
initializeModal($(this), '#clone-experiment-modal-' + id);
|
||||
});
|
||||
|
||||
// Bind modal to all actions listed on dropdown accesible from experiment
|
||||
// panel
|
||||
initializeDropdownActions();
|
||||
|
||||
// init
|
||||
initEditNoDescription();
|
||||
// Bind modals to all clone-experiment actions
|
||||
$.each($('.clone-experiment'), function() {
|
||||
var id = $(this).closest('.experiment-panel').data('id');
|
||||
initializeModal($(this), '#clone-experiment-modal-' + id);
|
||||
});
|
||||
|
||||
// Bind modal to all actions listed on dropdown accesible from experiment
|
||||
// panel
|
||||
initializeDropdownActions();
|
||||
|
||||
// init
|
||||
initEditNoDescription();
|
||||
})();
|
||||
|
|
|
@ -158,8 +158,12 @@
|
|||
});
|
||||
});
|
||||
}).on('shown.bs.modal', function() {
|
||||
var script = document.createElement('script');
|
||||
tagsInput.tagsinput('focus');
|
||||
recaptchaErrorMsgDiv.addClass('hidden');
|
||||
script.type = 'text/javascript';
|
||||
script.src = 'https://www.google.com/recaptcha/api.js?hl=en';
|
||||
$(script).insertAfter('#recaptcha-service');
|
||||
// Remove 'data-invited="true"' status
|
||||
modal.removeAttr('data-invited');
|
||||
}).on('hide.bs.modal', function() {
|
||||
|
@ -171,6 +175,7 @@
|
|||
teamSelectorDropdown2.addClass('disabled');
|
||||
animateSpinner(modalDialog, false);
|
||||
recaptchaErrorMsgDiv.addClass('hidden');
|
||||
$('#recaptcha-service').next().remove();
|
||||
|
||||
// Unbind event listeners
|
||||
teamSelectorCheckbox.off('change');
|
||||
|
|
|
@ -13,16 +13,6 @@
|
|||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&[data-unread="0"] {
|
||||
|
||||
.body-block {
|
||||
|
||||
.title {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $color-concrete;
|
||||
color: $color-emperor;
|
||||
|
|
|
@ -11,9 +11,20 @@ class Users::SessionsController < Devise::SessionsController
|
|||
end
|
||||
|
||||
# POST /resource/sign_in
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
def create
|
||||
super
|
||||
|
||||
# Schedule templates creation for user
|
||||
TemplatesService.new.schedule_creation_for_user(current_user)
|
||||
|
||||
# Schedule demo project creation for user
|
||||
current_user.created_teams.each do |team|
|
||||
FirstTimeDataGenerator.delay(
|
||||
queue: :new_demo_project,
|
||||
priority: 10
|
||||
).seed_demo_data_with_id(current_user.id, team.id)
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /resource/sign_out
|
||||
# def destroy
|
||||
|
|
|
@ -315,7 +315,7 @@ class Team < ApplicationRecord
|
|||
|
||||
def generate_template_project
|
||||
return if without_templates
|
||||
TemplatesService.new.update_team(self)
|
||||
TemplatesService.new.delay(queue: :templates).update_team(self)
|
||||
end
|
||||
|
||||
include FirstTimeDataGenerator
|
||||
|
|
|
@ -129,22 +129,10 @@ class TeamZipExport < ZipExport
|
|||
)
|
||||
file = FileUtils.touch("#{project_path}/#{html_name}").first
|
||||
File.open(file, 'wb') { |f| f.write(project_report_pdf) }
|
||||
|
||||
# Add Handsontable and dependent JS files (mimick frontend formula
|
||||
# processing).
|
||||
required_js = %w(handsontable.full.min.js lodash.js numeral.js numeric.js
|
||||
md5.js jstat.js formula.js parser.js ruleJS.js
|
||||
handsontable.formula.js big.min.js)
|
||||
required_js.each do |filename|
|
||||
filepath = File.join(Rails.root,
|
||||
"vendor/assets/javascripts/#{filename}/")
|
||||
dest_folder = "#{project_path}/"
|
||||
FileUtils.cp(filepath, dest_folder)
|
||||
end
|
||||
end
|
||||
|
||||
ensure
|
||||
# Change current dir outside tmp_dir, since tmp_dir will be deleted
|
||||
Dir.chdir(File.join(Rails.root, 'tmp'))
|
||||
Dir.chdir(Rails.root)
|
||||
end
|
||||
|
||||
def generate_notification(user)
|
||||
|
@ -152,6 +140,7 @@ class TeamZipExport < ZipExport
|
|||
type_of: :deliver,
|
||||
title: I18n.t('zip_export.notification_title'),
|
||||
message: "<a data-id='#{id}' " \
|
||||
"data-turbolinks='false' " \
|
||||
"href='#{Rails.application
|
||||
.routes
|
||||
.url_helpers
|
||||
|
|
|
@ -13,6 +13,7 @@ class UserProject < ApplicationRecord
|
|||
belongs_to :project, inverse_of: :user_projects, touch: true, optional: true
|
||||
|
||||
before_destroy :destroy_associations
|
||||
validates_uniqueness_of :user_id, scope: :project_id
|
||||
|
||||
def role_str
|
||||
I18n.t("user_projects.enums.role.#{role.to_s}")
|
||||
|
|
|
@ -14,6 +14,7 @@ class UserTeam < ApplicationRecord
|
|||
|
||||
before_destroy :destroy_associations
|
||||
after_create :create_samples_table_state
|
||||
validates_uniqueness_of :user_id, scope: :team_id
|
||||
|
||||
def role_str
|
||||
I18n.t("user_teams.enums.role.#{role}")
|
||||
|
|
|
@ -90,6 +90,7 @@ class ZipExport < ApplicationRecord
|
|||
type_of: :deliver,
|
||||
title: I18n.t('zip_export.notification_title'),
|
||||
message: "<a data-id='#{id}' " \
|
||||
"data-turbolinks='false' " \
|
||||
"href='#{Rails.application
|
||||
.routes
|
||||
.url_helpers
|
||||
|
|
|
@ -80,7 +80,7 @@ module Experiments
|
|||
user: @user,
|
||||
message: I18n.t(
|
||||
'activities.move_experiment',
|
||||
user: @user,
|
||||
user: @user.name,
|
||||
experiment: @exp.name,
|
||||
project_new: @project.name,
|
||||
project_original: @original_project.name
|
||||
|
|
|
@ -72,6 +72,7 @@ class ProjectsOverviewService
|
|||
.joins('LEFT OUTER JOIN user_projects ON '\
|
||||
'user_projects.project_id = projects.id')
|
||||
.left_outer_joins(:user_my_modules)
|
||||
.where('projects.id': @team.projects)
|
||||
.where('user_my_modules.user_id = :user_id '\
|
||||
'OR (user_projects.role = 0 '\
|
||||
'AND user_projects.user_id = :user_id)', user_id: @user.id)
|
||||
|
|
|
@ -32,13 +32,16 @@ class TemplatesService
|
|||
return unless owner.present?
|
||||
updated = false
|
||||
exp_tmplt_dir_prefix = "#{@base_dir}/experiment_"
|
||||
existing = tmpl_project.experiments.where.not(uuid: nil).pluck(:uuid)
|
||||
@experiment_templates.except(*existing).each_value do |id|
|
||||
importer_service = TeamImporter.new
|
||||
importer_service.import_experiment_template_from_dir(
|
||||
exp_tmplt_dir_prefix + id.to_s, tmpl_project.id, owner.id
|
||||
)
|
||||
updated = true
|
||||
# Create lock in case another worker starts to update same team
|
||||
tmpl_project.with_lock do
|
||||
existing = tmpl_project.experiments.where.not(uuid: nil).pluck(:uuid)
|
||||
@experiment_templates.except(*existing).each_value do |id|
|
||||
importer_service = TeamImporter.new
|
||||
importer_service.import_experiment_template_from_dir(
|
||||
exp_tmplt_dir_prefix + id.to_s, tmpl_project.id, owner.id
|
||||
)
|
||||
updated = true
|
||||
end
|
||||
end
|
||||
updated
|
||||
end
|
||||
|
@ -52,4 +55,14 @@ class TemplatesService
|
|||
end
|
||||
[updated_counter, processed_counter]
|
||||
end
|
||||
|
||||
def schedule_creation_for_user(user)
|
||||
user.teams.each do |team|
|
||||
next if team.projects.where(template: true).any?
|
||||
|
||||
TemplatesService.new.delay(
|
||||
queue: :templates
|
||||
).update_team(team)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,8 @@ module DelayedUploaderDemo
|
|||
current_team:,
|
||||
result_name:,
|
||||
created_at: Time.now,
|
||||
file_name:
|
||||
file_name:,
|
||||
comment: nil
|
||||
)
|
||||
temp_asset = get_asset(current_user, current_team, file_name)
|
||||
temp_result = Result.new(
|
||||
|
@ -32,6 +33,10 @@ module DelayedUploaderDemo
|
|||
|
||||
temp_result.save
|
||||
temp_asset.save
|
||||
|
||||
# Generate comment if it exists
|
||||
generate_result_comment(temp_result, current_user, comment) if comment
|
||||
|
||||
temp_asset.post_process_file(my_module.experiment.project.team)
|
||||
|
||||
# Create result activity
|
||||
|
@ -57,4 +62,25 @@ module DelayedUploaderDemo
|
|||
step.assets << temp_asset
|
||||
temp_asset.post_process_file(step.my_module.experiment.project.team)
|
||||
end
|
||||
|
||||
def self.generate_result_comment(result, user, message, created_at = nil)
|
||||
created_at ||= result.created_at
|
||||
ResultComment.create(
|
||||
user: user,
|
||||
message: message,
|
||||
created_at: created_at,
|
||||
result: result
|
||||
)
|
||||
Activity.new(
|
||||
type_of: :add_comment_to_result,
|
||||
user: user,
|
||||
project: result.my_module.experiment.project,
|
||||
my_module: result.my_module,
|
||||
created_at: created_at,
|
||||
updated_at: created_at,
|
||||
message: I18n.t('activities.add_comment_to_result',
|
||||
user: user.full_name,
|
||||
result: result.name)
|
||||
).sneaky_save
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,37 @@ module FirstTimeDataGenerator
|
|||
# Do nothing
|
||||
return unless team
|
||||
|
||||
# Skip this team if user already has a demo project
|
||||
return if team.projects.where(demo: true).any?
|
||||
|
||||
name = '[NEW] Demo project by SciNote'
|
||||
exp_name = 'Polymerase chain reaction'
|
||||
# If there is an existing demo project, archive and rename it
|
||||
if team.projects.where(name: name).present?
|
||||
# TODO: check if we still need this code
|
||||
# old = team.projects.where(name: 'Demo project - qPCR')[0]
|
||||
# old.archive! user
|
||||
i = 1
|
||||
while team.projects.where(
|
||||
name: name = "#{name} (#{i})"
|
||||
).present?
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
project = Project.create(
|
||||
visibility: 0,
|
||||
name: name,
|
||||
due_date: nil,
|
||||
team: team,
|
||||
created_by: user,
|
||||
created_at: generate_random_time(1.week.ago),
|
||||
last_modified_by: user,
|
||||
archived: false,
|
||||
template: false,
|
||||
demo: true
|
||||
)
|
||||
|
||||
# check if samples repo already exist, then create custom repository samples
|
||||
repository = Repository.where(team: team).where(name: REPO_SAMPLES_NAME)
|
||||
repository =
|
||||
|
@ -192,32 +223,6 @@ module FirstTimeDataGenerator
|
|||
)
|
||||
end
|
||||
|
||||
name = '[NEW] Demo project by SciNote'
|
||||
exp_name = 'Polymerase chain reaction'
|
||||
# If there is an existing demo project, archive and rename it
|
||||
if team.projects.where(name: name).present?
|
||||
# TODO: check if we still need this code
|
||||
# old = team.projects.where(name: 'Demo project - qPCR')[0]
|
||||
# old.archive! user
|
||||
i = 1
|
||||
while team.projects.where(
|
||||
name: name = "#{name} (#{i})"
|
||||
).present?
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
project = Project.create(
|
||||
visibility: 0,
|
||||
name: name,
|
||||
due_date: nil,
|
||||
team: team,
|
||||
created_by: user,
|
||||
created_at: generate_random_time(1.week.ago),
|
||||
last_modified_by: user,
|
||||
archived: false
|
||||
)
|
||||
|
||||
experiment_description =
|
||||
'Polymerase chain reaction (PCR) monitors the amplification of DNA ' \
|
||||
'in real time (qPCR cyclers constantly scan qPCR plates). It is, in ' \
|
||||
|
@ -360,75 +365,6 @@ module FirstTimeDataGenerator
|
|||
).sneaky_save
|
||||
end
|
||||
|
||||
# Create an archived module
|
||||
archived_module = MyModule.create(
|
||||
name: 'Data analysis - Pfaffl method',
|
||||
created_by: user,
|
||||
created_at: generate_random_time(6.days.ago),
|
||||
due_date: Time.now + 1.week,
|
||||
description: nil,
|
||||
x: -1,
|
||||
y: -1,
|
||||
experiment: experiment,
|
||||
workflow_order: -1,
|
||||
my_module_group: nil,
|
||||
archived: true,
|
||||
archived_on: generate_random_time(3.days.ago),
|
||||
archived_by: user
|
||||
)
|
||||
|
||||
# Activity for creating archived module
|
||||
Activity.new(
|
||||
type_of: :create_module,
|
||||
user: user,
|
||||
project: project,
|
||||
my_module: archived_module,
|
||||
message: I18n.t(
|
||||
'activities.create_module',
|
||||
user: user.full_name,
|
||||
module: archived_module.name
|
||||
),
|
||||
created_at: archived_module.created_at,
|
||||
updated_at: archived_module.created_at
|
||||
).sneaky_save
|
||||
|
||||
# Activity for archiving archived module
|
||||
Activity.new(
|
||||
type_of: :archive_module,
|
||||
user: user,
|
||||
project: project,
|
||||
my_module: archived_module,
|
||||
message: I18n.t(
|
||||
'activities.archive_module',
|
||||
user: user.full_name,
|
||||
module: archived_module.name
|
||||
),
|
||||
created_at: archived_module.archived_on,
|
||||
updated_at: archived_module.archived_on
|
||||
).sneaky_save
|
||||
|
||||
# Assign new user to archived module
|
||||
UserMyModule.create(
|
||||
user: user,
|
||||
my_module: archived_module,
|
||||
assigned_by: user,
|
||||
created_at: generate_random_time(archived_module.created_at, 2.minutes)
|
||||
)
|
||||
Activity.new(
|
||||
type_of: :assign_user_to_module,
|
||||
user: user,
|
||||
project: project,
|
||||
my_module: archived_module,
|
||||
message: I18n.t(
|
||||
'activities.assign_user_to_module',
|
||||
assigned_user: user.full_name,
|
||||
module: archived_module.name,
|
||||
assigned_by_user: user.full_name
|
||||
),
|
||||
created_at: generate_random_time(archived_module.created_at, 2.minutes),
|
||||
updated_at: generate_random_time(archived_module.created_at, 2.minutes)
|
||||
).sneaky_save
|
||||
|
||||
# Assign 4 samples to modules
|
||||
samples_to_assign = []
|
||||
taken_sample_ids = []
|
||||
|
@ -798,11 +734,12 @@ module FirstTimeDataGenerator
|
|||
user: user
|
||||
)
|
||||
qpcr_id = MyModule.where(name: 'qPCR').last.id.base62_encode
|
||||
generate_result_comment(
|
||||
DelayedUploaderDemo.generate_result_comment(
|
||||
temp_result,
|
||||
user,
|
||||
user_annotation + ' Please check if results match results in ' \
|
||||
'[#qPCR~tsk~' + qpcr_id + ']'
|
||||
'[#qPCR~tsk~' + qpcr_id + ']',
|
||||
generate_random_time(temp_result.created_at, 1.days)
|
||||
)
|
||||
temp_result.table = Table.new(
|
||||
created_by: user,
|
||||
|
@ -833,7 +770,8 @@ module FirstTimeDataGenerator
|
|||
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'
|
||||
file_name: 'totRNA_gel.jpg',
|
||||
comment: user_annotation + ' Could you check if this is okay?'
|
||||
)
|
||||
|
||||
# ----------------- Module 4 ------------------
|
||||
|
@ -955,8 +893,8 @@ module FirstTimeDataGenerator
|
|||
'If desired, more than 30 mg tissue can be disrupted and homogenized ' \
|
||||
'at the start of the procedure (increase the volume of Buffer RLT ' \
|
||||
'proportionately). Use a portion of the homogenate corresponding to no ' \
|
||||
'more than 30 mg tissue for RNA purification, and store the rest at –80',
|
||||
'°C. Buffer RLT may form a precipitate upon storage. If necessary, ' \
|
||||
'more than 30 mg tissue for RNA purification, and store the rest at –80°C.',
|
||||
'Buffer RLT may form a precipitate upon storage. If necessary, ' \
|
||||
'redissolve by warming, and then place at room temperature (15–25°C).',
|
||||
'Buffer RLT and Buffer RW1 contain a guanidine salt and are therefore ' \
|
||||
'not compatible with disinfecting reagents containing bleach. See page ' \
|
||||
|
@ -1249,7 +1187,11 @@ module FirstTimeDataGenerator
|
|||
current_team: team,
|
||||
result_name: 'Bacteria plates YPGA',
|
||||
created_at: generate_random_time(my_modules[5].created_at, 2.days),
|
||||
file_name: 'Bacterial_colonies.jpg'
|
||||
file_name: 'Bacterial_colonies.jpg',
|
||||
comment: user_annotation + ' please check the results again. ' \
|
||||
'<span class=\"atwho-inserted\" contenteditable=\"false\"' \
|
||||
'data-atwho-at-query=\"#\">[#' + fifth_rep_item + ']</span>' \
|
||||
' seems to be acting strange?'
|
||||
)
|
||||
|
||||
DelayedUploaderDemo.delay(queue: asset_queue).generate_result_asset(
|
||||
|
@ -1611,9 +1553,9 @@ module FirstTimeDataGenerator
|
|||
if rand < 0.3
|
||||
polite_comment = 'This looks well.'
|
||||
elsif rand < 0.4
|
||||
polite_comment = 'Seems satisfactory.'
|
||||
polite_comment = 'Great job!'
|
||||
elsif rand < 0.4
|
||||
polite_comment = 'Try a bit harder next time.'
|
||||
polite_comment = 'Thanks for getting this done.'
|
||||
end
|
||||
if polite_comment
|
||||
commented_on = generate_random_time(completed_on)
|
||||
|
@ -1669,27 +1611,6 @@ module FirstTimeDataGenerator
|
|||
).sneaky_save
|
||||
end
|
||||
|
||||
def generate_result_comment(result, user, message, created_at = nil)
|
||||
created_at ||= generate_random_time(result.created_at, 1.days)
|
||||
ResultComment.create(
|
||||
user: user,
|
||||
message: message,
|
||||
created_at: created_at,
|
||||
result: result
|
||||
)
|
||||
Activity.new(
|
||||
type_of: :add_comment_to_result,
|
||||
user: user,
|
||||
project: result.my_module.experiment.project,
|
||||
my_module: result.my_module,
|
||||
created_at: created_at,
|
||||
updated_at: created_at,
|
||||
message: I18n.t('activities.add_comment_to_result',
|
||||
user: user.full_name,
|
||||
result: result.name)
|
||||
).sneaky_save
|
||||
end
|
||||
|
||||
def generate_step_comment(step, user, message, created_at = nil)
|
||||
created_at ||= generate_random_time(step.created_at, 2.hours)
|
||||
StepComment.create(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="row first-row">
|
||||
<div class="col-xs-6 col-sm-6 col-md-4 col-lg-4 date-block">
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-6 col-md-4">
|
||||
<div class="badge-icon">
|
||||
<span class="fas fa-calendar-alt"></span>
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6 col-sm-6 col-md-4 col-lg-4 help_tooltips date-block"
|
||||
<div class="col-xs-6 col-sm-6 col-md-4 help_tooltips"
|
||||
data-tooltiplink="<%= I18n.t('tooltips.link.task.due_date_specific') %>"
|
||||
data-tooltipcontent="<%= I18n.t('tooltips.text.task.due_date_specific') %>">
|
||||
<div class="badge-icon">
|
||||
|
@ -39,13 +39,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6 col-sm-6 col-md-3 complete-button-container">
|
||||
<%= render partial: "my_modules/state_buttons.html.erb" %>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6 col-sm-6 col-md-4 col-lg-3">
|
||||
<div class="col-xs-6 col-sm-6 col-md-4">
|
||||
<div class="badge-icon">
|
||||
<span class="fas fa-tachometer-alt"></span>
|
||||
<span class="fas fa-check"></span>
|
||||
</div>
|
||||
<div class="well well-sm">
|
||||
<span class="task-state-label">
|
||||
|
@ -54,7 +50,6 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row module-tags">
|
||||
<div class="col-xs-12 col-sm-12 col-md-12" id="module-tags" data-module-tags-url="<%= my_module_my_module_tags_url(@my_module, format: :json) %>">
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
} %>
|
||||
|
||||
<div class="content-pane my-modules-protocols-index">
|
||||
<div class="content-pane">
|
||||
<%= render partial: "module_header" %>
|
||||
|
||||
<div>
|
||||
|
@ -21,6 +21,7 @@
|
|||
<%= render partial: "my_modules/protocols/protocol_status_bar.html.erb" %>
|
||||
</div>
|
||||
<%= render partial: "my_modules/protocols/protocol_buttons.html.erb" %>
|
||||
<%= render partial: "my_modules/state_buttons.html.erb" %>
|
||||
</div>
|
||||
|
||||
<div data-role="steps-container">
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<button type="button" class="preview-close" data-dismiss="modal"><span class="fas fa-times"></span></button>
|
||||
<span class="file-name"></span>
|
||||
<span class="file-wopi-controls"></span>
|
||||
<a class="file-download-link" href='#'>
|
||||
<a class="file-download-link" href="#" data-turbolinks="false">
|
||||
<p><span class="fas fa-download"></span> <%= t('Download')%></p>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -103,7 +103,6 @@ invite_to_team = type.in?(%w(invite_to_team invite_to_team_with_role))
|
|||
<div id="recaptcha-service" class="g-recaptcha"
|
||||
data-callback="recaptchaCallback"
|
||||
data-sitekey=<%= ENV['RECAPTCHA_SITE_KEY'] %>></div>
|
||||
<script type="text/javascript" src="https://www.google.com/recaptcha/api.js?hl=en"></script>
|
||||
<input type="hidden" id="recaptcha-invite-modal" value="">
|
||||
<div class="form-group has-error hidden" id="recaptcha-error-msg" >
|
||||
<span class="has-error help-block"></span>
|
||||
|
|
|
@ -11,19 +11,20 @@
|
|||
.html_safe %>
|
||||
</style>
|
||||
|
||||
<script src="handsontable.full.min.js"></script>
|
||||
|
||||
<!-- Libraries for formulas -->
|
||||
<script src="lodash.js"></script>
|
||||
<script src="numeral.js"></script>
|
||||
<script src="numeric.js"></script>
|
||||
<script src="md5.js"></script>
|
||||
<script src="jstat.js"></script>
|
||||
<script src="formula.js"></script>
|
||||
<script src="parser.js"></script>
|
||||
<script src="ruleJS.js"></script>
|
||||
<script src="handsontable.formula.js"></script>
|
||||
<script src="big.min.js"></script>
|
||||
<!-- Libraries for tables and formulas -->
|
||||
<% ['handsontable.full.min.js', 'lodash.js', 'numeral.js', 'numeric.js',
|
||||
'md5.js', 'jstat.js', 'formula.js', 'parser.js', 'ruleJS.js',
|
||||
'handsontable.formula.js', 'big.min.js' ].each do |js_asset| %>
|
||||
<script type="text/javascript">
|
||||
<%= Rails.application
|
||||
.assets_manifest
|
||||
.find_sources(js_asset)
|
||||
.first
|
||||
.to_s
|
||||
.force_encoding(Encoding::UTF_8)
|
||||
.html_safe %>
|
||||
</script>
|
||||
<% end %>
|
||||
|
||||
<!-- Init Handsontables -->
|
||||
<script>
|
||||
|
|
|
@ -224,10 +224,10 @@ class Constants
|
|||
span u s blockquote pre col colgroup table thead tbody th tr td
|
||||
).freeze
|
||||
|
||||
WHITELISTED_ATTRIBUTES = %w(
|
||||
href src width height alt cite datetime title class name xml:lang abbr style
|
||||
target data-*
|
||||
).freeze
|
||||
WHITELISTED_ATTRIBUTES = [
|
||||
'href', 'src', 'width', 'height', 'alt', 'cite', 'datetime', 'title',
|
||||
'class', 'name', 'xml:lang', 'abbr', 'style', 'target', :data
|
||||
].freeze
|
||||
|
||||
WHITELISTED_CSS_ATTRIBUTES = {
|
||||
allow_comments: false,
|
||||
|
|
16
db/migrate/20190227125306_add_unique_index_on_user_teams.rb
Normal file
16
db/migrate/20190227125306_add_unique_index_on_user_teams.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddUniqueIndexOnUserTeams < ActiveRecord::Migration[5.1]
|
||||
def up
|
||||
# firstly delete the duplicates
|
||||
execute 'WITH uniq AS
|
||||
(SELECT DISTINCT ON (user_id, team_id) * FROM user_teams)
|
||||
DELETE FROM user_teams WHERE user_teams.id NOT IN
|
||||
(SELECT id FROM uniq)'
|
||||
add_index :user_teams, %i(user_id team_id), unique: true
|
||||
end
|
||||
|
||||
def down
|
||||
remove_index :user_teams, column: %i(user_id team_id)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddUniqueIndexOnUserProjects < ActiveRecord::Migration[5.1]
|
||||
def up
|
||||
# firstly delete the duplicates
|
||||
execute 'WITH uniq AS
|
||||
(SELECT DISTINCT ON (user_id, project_id) * FROM user_projects)
|
||||
DELETE FROM user_projects WHERE user_projects.id NOT IN
|
||||
(SELECT id FROM uniq)'
|
||||
add_index :user_projects, %i(user_id project_id), unique: true
|
||||
end
|
||||
|
||||
def down
|
||||
remove_index :user_projects, columns: %i(user_id project_id)
|
||||
end
|
||||
end
|
6
db/migrate/20190304153544_add_demo_flag_to_project.rb
Normal file
6
db/migrate/20190304153544_add_demo_flag_to_project.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
class AddDemoFlagToProject < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :projects, :demo, :boolean, null: false, default: false
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20190125123107) do
|
||||
ActiveRecord::Schema.define(version: 20190304153544) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -298,6 +298,7 @@ ActiveRecord::Schema.define(version: 20190125123107) do
|
|||
t.datetime "restored_on"
|
||||
t.string "experiments_order"
|
||||
t.boolean "template"
|
||||
t.boolean "demo", default: false, null: false
|
||||
t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_projects_on_name", using: :gin
|
||||
t.index ["archived_by_id"], name: "index_projects_on_archived_by_id"
|
||||
t.index ["created_by_id"], name: "index_projects_on_created_by_id"
|
||||
|
@ -796,6 +797,7 @@ ActiveRecord::Schema.define(version: 20190125123107) do
|
|||
t.bigint "assigned_by_id"
|
||||
t.index ["assigned_by_id"], name: "index_user_projects_on_assigned_by_id"
|
||||
t.index ["project_id"], name: "index_user_projects_on_project_id"
|
||||
t.index ["user_id", "project_id"], name: "index_user_projects_on_user_id_and_project_id", unique: true
|
||||
t.index ["user_id"], name: "index_user_projects_on_user_id"
|
||||
end
|
||||
|
||||
|
@ -821,6 +823,7 @@ ActiveRecord::Schema.define(version: 20190125123107) do
|
|||
t.bigint "assigned_by_id"
|
||||
t.index ["assigned_by_id"], name: "index_user_teams_on_assigned_by_id"
|
||||
t.index ["team_id"], name: "index_user_teams_on_team_id"
|
||||
t.index ["user_id", "team_id"], name: "index_user_teams_on_user_id_and_team_id", unique: true
|
||||
t.index ["user_id"], name: "index_user_teams_on_user_id"
|
||||
end
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@ describe ClientApi::UserTeamService do
|
|||
|
||||
describe '#update_role!' do
|
||||
it 'should raise ClientApi::CustomUserTeamError if no role is set' do
|
||||
create :user_team, team: team_one, user: user_one
|
||||
ut_service = ClientApi::UserTeamService.new(
|
||||
user: user_one,
|
||||
team_id: team_one.id,
|
||||
|
|
Loading…
Reference in a new issue