mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-10 00:11:22 +08:00
Merge branch 'master' into rails-5.1
Conflicts: Gemfile.lock app/datatables/repository_datatable.rb app/models/repository_cell.rb
This commit is contained in:
commit
ae5bccf709
36 changed files with 1332 additions and 1115 deletions
3
Gemfile
3
Gemfile
|
|
@ -51,7 +51,7 @@ gem 'ajax-datatables-rails', '~> 0.3.1'
|
||||||
gem 'commit_param_routing' # Enables different submit actions in the same form to route to different actions in controller
|
gem 'commit_param_routing' # Enables different submit actions in the same form to route to different actions in controller
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
gem "i18n-js", ">= 3.0.0.rc11" # Localization in javascript files
|
gem "i18n-js", ">= 3.0.0.rc11" # Localization in javascript files
|
||||||
gem 'roo', '~> 2.1.0' # Spreadsheet parser
|
gem 'roo', '~> 2.7.1' # Spreadsheet parser
|
||||||
gem 'wicked_pdf'
|
gem 'wicked_pdf'
|
||||||
gem 'silencer' # Silence certain Rails logs
|
gem 'silencer' # Silence certain Rails logs
|
||||||
gem 'wkhtmltopdf-heroku'
|
gem 'wkhtmltopdf-heroku'
|
||||||
|
|
@ -64,6 +64,7 @@ gem 'sneaky-save', git: 'https://github.com/einzige/sneaky-save'
|
||||||
gem 'rails_autolink', '~> 1.1', '>= 1.1.6'
|
gem 'rails_autolink', '~> 1.1', '>= 1.1.6'
|
||||||
gem 'delayed_paperclip'
|
gem 'delayed_paperclip'
|
||||||
gem 'rubyzip'
|
gem 'rubyzip'
|
||||||
|
gem 'activerecord-import'
|
||||||
|
|
||||||
gem 'paperclip', '~> 5.1' # File attachment, image attachment library
|
gem 'paperclip', '~> 5.1' # File attachment, image attachment library
|
||||||
gem 'aws-sdk', '~> 2'
|
gem 'aws-sdk', '~> 2'
|
||||||
|
|
|
||||||
61
Gemfile.lock
61
Gemfile.lock
|
|
@ -7,7 +7,7 @@ GIT
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/einzige/sneaky-save
|
remote: https://github.com/einzige/sneaky-save
|
||||||
revision: e7c77674abe74d598dfd58db7c680dd85936f207
|
revision: 7e7596720e76a3c243042be2f5f916525b143a54
|
||||||
specs:
|
specs:
|
||||||
sneaky-save (0.1.2)
|
sneaky-save (0.1.2)
|
||||||
activerecord (>= 3.2.0)
|
activerecord (>= 3.2.0)
|
||||||
|
|
@ -56,6 +56,8 @@ GEM
|
||||||
activemodel (= 5.1.1)
|
activemodel (= 5.1.1)
|
||||||
activesupport (= 5.1.1)
|
activesupport (= 5.1.1)
|
||||||
arel (~> 8.0)
|
arel (~> 8.0)
|
||||||
|
activerecord-import (0.19.1)
|
||||||
|
activerecord (>= 3.2)
|
||||||
activesupport (5.1.1)
|
activesupport (5.1.1)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
|
|
@ -70,26 +72,28 @@ GEM
|
||||||
ast (2.3.0)
|
ast (2.3.0)
|
||||||
auto_strip_attributes (2.1.0)
|
auto_strip_attributes (2.1.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
autoprefixer-rails (7.1.1.2)
|
autoprefixer-rails (7.1.2.4)
|
||||||
execjs
|
execjs
|
||||||
autosize-rails (1.18.17)
|
autosize-rails (1.18.17)
|
||||||
rails (>= 3.1)
|
rails (>= 3.1)
|
||||||
awesome_print (1.8.0)
|
awesome_print (1.8.0)
|
||||||
aws-sdk (2.2.37)
|
aws-sdk (2.10.21)
|
||||||
aws-sdk-resources (= 2.2.37)
|
aws-sdk-resources (= 2.10.21)
|
||||||
aws-sdk-core (2.2.37)
|
aws-sdk-core (2.10.21)
|
||||||
|
aws-sigv4 (~> 1.0)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-resources (2.2.37)
|
aws-sdk-resources (2.10.21)
|
||||||
aws-sdk-core (= 2.2.37)
|
aws-sdk-core (= 2.10.21)
|
||||||
|
aws-sigv4 (1.0.1)
|
||||||
babel-source (5.8.35)
|
babel-source (5.8.35)
|
||||||
babel-transpiler (0.7.0)
|
babel-transpiler (0.7.0)
|
||||||
babel-source (>= 4.0, < 6)
|
babel-source (>= 4.0, < 6)
|
||||||
execjs (~> 2.0)
|
execjs (~> 2.0)
|
||||||
base62 (1.0.0)
|
base62 (1.0.0)
|
||||||
bcrypt (3.1.11)
|
bcrypt (3.1.11)
|
||||||
better_errors (2.1.1)
|
better_errors (2.3.0)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
erubis (>= 2.6.6)
|
erubi (>= 1.0.0)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
binding_of_caller (0.7.2)
|
binding_of_caller (0.7.2)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
|
|
@ -102,9 +106,9 @@ GEM
|
||||||
bootstrap_form (2.7.0)
|
bootstrap_form (2.7.0)
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
byebug (9.0.6)
|
byebug (9.0.6)
|
||||||
capybara (2.14.4)
|
capybara (2.15.1)
|
||||||
addressable
|
addressable
|
||||||
mime-types (>= 1.16)
|
mini_mime (>= 0.1.3)
|
||||||
nokogiri (>= 1.3.3)
|
nokogiri (>= 1.3.3)
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.5.4)
|
||||||
|
|
@ -169,15 +173,14 @@ GEM
|
||||||
devise (>= 4.0.0)
|
devise (>= 4.0.0)
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.3)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
erubi (1.6.0)
|
erubi (1.6.1)
|
||||||
erubis (2.7.0)
|
|
||||||
execjs (2.7.0)
|
execjs (2.7.0)
|
||||||
factory_girl (4.8.0)
|
factory_girl (4.8.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
factory_girl_rails (4.8.0)
|
factory_girl_rails (4.8.0)
|
||||||
factory_girl (~> 4.8.0)
|
factory_girl (~> 4.8.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
faker (1.7.3)
|
faker (1.8.4)
|
||||||
i18n (~> 0.5)
|
i18n (~> 0.5)
|
||||||
ffi (1.9.18)
|
ffi (1.9.18)
|
||||||
figaro (1.1.1)
|
figaro (1.1.1)
|
||||||
|
|
@ -188,8 +191,8 @@ GEM
|
||||||
globalid (0.4.0)
|
globalid (0.4.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
hammerjs-rails (2.0.4)
|
hammerjs-rails (2.0.4)
|
||||||
i18n (0.8.4)
|
i18n (0.8.6)
|
||||||
i18n-js (3.0.0)
|
i18n-js (3.0.1)
|
||||||
i18n (~> 0.6, >= 0.6.6)
|
i18n (~> 0.6, >= 0.6.6)
|
||||||
introjs-rails (1.0.0)
|
introjs-rails (1.0.0)
|
||||||
sass-rails (>= 3.2)
|
sass-rails (>= 3.2)
|
||||||
|
|
@ -236,17 +239,18 @@ GEM
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (1.25.1)
|
mime-types (1.25.1)
|
||||||
mimemagic (0.3.2)
|
mimemagic (0.3.2)
|
||||||
|
mini_mime (0.1.3)
|
||||||
mini_portile2 (2.2.0)
|
mini_portile2 (2.2.0)
|
||||||
minitest (5.10.2)
|
minitest (5.10.3)
|
||||||
momentjs-rails (2.17.1)
|
momentjs-rails (2.17.1)
|
||||||
railties (>= 3.1)
|
railties (>= 3.1)
|
||||||
multi_json (1.12.1)
|
multi_json (1.12.1)
|
||||||
multi_test (0.1.2)
|
multi_test (0.1.2)
|
||||||
nested_form_fields (0.8)
|
nested_form_fields (0.8.1)
|
||||||
coffee-rails (>= 3.2.1)
|
coffee-rails (>= 3.2.1)
|
||||||
jquery-rails
|
jquery-rails
|
||||||
rails (>= 3.2.0)
|
rails (>= 3.2.0)
|
||||||
newrelic_rpm (4.2.0.334)
|
newrelic_rpm (4.3.0.335)
|
||||||
nio4r (2.1.0)
|
nio4r (2.1.0)
|
||||||
nokogiri (1.8.0)
|
nokogiri (1.8.0)
|
||||||
mini_portile2 (~> 2.2.0)
|
mini_portile2 (~> 2.2.0)
|
||||||
|
|
@ -260,7 +264,7 @@ GEM
|
||||||
cocaine (~> 0.5.5)
|
cocaine (~> 0.5.5)
|
||||||
mime-types
|
mime-types
|
||||||
mimemagic (~> 0.3.0)
|
mimemagic (~> 0.3.0)
|
||||||
parallel (1.11.2)
|
parallel (1.12.0)
|
||||||
parser (2.4.0.0)
|
parser (2.4.0.0)
|
||||||
ast (~> 2.2)
|
ast (~> 2.2)
|
||||||
pg (0.21.0)
|
pg (0.21.0)
|
||||||
|
|
@ -318,7 +322,7 @@ GEM
|
||||||
rainbow (2.2.2)
|
rainbow (2.2.2)
|
||||||
rake
|
rake
|
||||||
rake (12.0.0)
|
rake (12.0.0)
|
||||||
rb-fsevent (0.9.8)
|
rb-fsevent (0.10.2)
|
||||||
rb-inotify (0.9.10)
|
rb-inotify (0.9.10)
|
||||||
ffi (>= 0.5.0, < 2)
|
ffi (>= 0.5.0, < 2)
|
||||||
rdoc (4.3.0)
|
rdoc (4.3.0)
|
||||||
|
|
@ -332,7 +336,7 @@ GEM
|
||||||
lazy_priority_queue (~> 0.1.0)
|
lazy_priority_queue (~> 0.1.0)
|
||||||
stream (~> 0.5.0)
|
stream (~> 0.5.0)
|
||||||
rkelly-remix (0.0.7)
|
rkelly-remix (0.0.7)
|
||||||
roo (2.1.1)
|
roo (2.7.1)
|
||||||
nokogiri (~> 1)
|
nokogiri (~> 1)
|
||||||
rubyzip (~> 1.1, < 2.0.0)
|
rubyzip (~> 1.1, < 2.0.0)
|
||||||
rspec-core (3.6.0)
|
rspec-core (3.6.0)
|
||||||
|
|
@ -367,7 +371,7 @@ GEM
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.4.4)
|
nokogiri (>= 1.4.4)
|
||||||
nokogumbo (~> 1.4.1)
|
nokogumbo (~> 1.4.1)
|
||||||
sass (3.4.24)
|
sass (3.4.25)
|
||||||
sass-rails (5.0.6)
|
sass-rails (5.0.6)
|
||||||
railties (>= 4.0.0, < 6)
|
railties (>= 4.0.0, < 6)
|
||||||
sass (~> 3.1)
|
sass (~> 3.1)
|
||||||
|
|
@ -380,7 +384,7 @@ GEM
|
||||||
sdoc (0.4.2)
|
sdoc (0.4.2)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
rdoc (~> 4.0)
|
rdoc (~> 4.0)
|
||||||
shoulda-matchers (3.1.1)
|
shoulda-matchers (3.1.2)
|
||||||
activesupport (>= 4.0.0)
|
activesupport (>= 4.0.0)
|
||||||
silencer (1.0.1)
|
silencer (1.0.1)
|
||||||
simple_token_authentication (1.15.1)
|
simple_token_authentication (1.15.1)
|
||||||
|
|
@ -413,8 +417,8 @@ GEM
|
||||||
stream (0.5)
|
stream (0.5)
|
||||||
thor (0.19.4)
|
thor (0.19.4)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.7)
|
tilt (2.0.8)
|
||||||
tinymce-rails (4.6.4)
|
tinymce-rails (4.6.5)
|
||||||
railties (>= 3.1.1)
|
railties (>= 3.1.1)
|
||||||
turbolinks (5.0.1)
|
turbolinks (5.0.1)
|
||||||
turbolinks-source (~> 5)
|
turbolinks-source (~> 5)
|
||||||
|
|
@ -446,6 +450,7 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
activerecord-import
|
||||||
ajax-datatables-rails (~> 0.3.1)
|
ajax-datatables-rails (~> 0.3.1)
|
||||||
aspector
|
aspector
|
||||||
auto_strip_attributes (~> 2.1)
|
auto_strip_attributes (~> 2.1)
|
||||||
|
|
@ -506,7 +511,7 @@ DEPENDENCIES
|
||||||
recaptcha
|
recaptcha
|
||||||
remotipart (~> 1.2)
|
remotipart (~> 1.2)
|
||||||
rgl
|
rgl
|
||||||
roo (~> 2.1.0)
|
roo (~> 2.7.1)
|
||||||
rspec-rails
|
rspec-rails
|
||||||
rubocop
|
rubocop
|
||||||
ruby-graphviz (~> 1.2)
|
ruby-graphviz (~> 1.2)
|
||||||
|
|
@ -536,4 +541,4 @@ RUBY VERSION
|
||||||
ruby 2.4.1p111
|
ruby 2.4.1p111
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.15.1
|
1.15.3
|
||||||
|
|
|
||||||
1
VERSION
Normal file
1
VERSION
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
1.12.3
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
$('#form-records-file').on('ajax:success', function(ev, data) {
|
$('#form-records-file').on('ajax:success', function(ev, data) {
|
||||||
$('#modal-import-records').modal('hide');
|
$('#modal-import-records').modal('hide');
|
||||||
$(data.html).appendTo('body').promise().done(function() {
|
$(data.html).appendTo('body').promise().done(function() {
|
||||||
$('#parse-records_modal')
|
$('#parse-records-modal')
|
||||||
.modal('show')
|
.modal('show')
|
||||||
.on('hidden.bs.modal', function() {
|
.on('hidden.bs.modal', function() {
|
||||||
animateSpinner();
|
animateSpinner();
|
||||||
|
|
@ -26,6 +26,11 @@
|
||||||
});
|
});
|
||||||
repositoryRecordsImporter();
|
repositoryRecordsImporter();
|
||||||
});
|
});
|
||||||
|
}).on('ajax:error', function(ev, data) {
|
||||||
|
$(this).find('.form-group').addClass('has-error');
|
||||||
|
$(this).find('.form-group').find('.help-block').remove();
|
||||||
|
$(this).find('.form-group').append("<span class='help-block'>" +
|
||||||
|
data.responseJSON.message + '</span>');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,8 +46,10 @@
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
var tabBody = $(pane.context.hash).find(".tab-content-body");
|
var tabBody = $(pane.context.hash).find(".tab-content-body");
|
||||||
tabBody.html(data.html);
|
tabBody.html(data.html);
|
||||||
pane.tab('show').promise().done(function() {
|
pane.tab('show').promise().done(function(el) {
|
||||||
initImportRecordsModal();
|
initImportRecordsModal();
|
||||||
|
RepositoryDatatable.destroy()
|
||||||
|
RepositoryDatatable.init(el.attr('data-repo-table'));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error: function (error) {
|
||||||
|
|
|
||||||
10
app/assets/javascripts/repositories/my_module_repository.js
Normal file
10
app/assets/javascripts/repositories/my_module_repository.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// initialze repository datatable
|
||||||
|
$(document).ready(function() {
|
||||||
|
RepositoryDatatable.destroy()
|
||||||
|
RepositoryDatatable.init($('#content').attr('data-repo-id'));
|
||||||
|
onClickToggleAssignedRecords();
|
||||||
|
});
|
||||||
|
})();
|
||||||
File diff suppressed because it is too large
Load diff
9
app/assets/javascripts/sitewide/about_modal.js
Normal file
9
app/assets/javascripts/sitewide/about_modal.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$("[data-trigger='about-modal']").on('click', function() {
|
||||||
|
$('[data-role=about-modal]').modal('show');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
@ -424,6 +424,11 @@ var SmartAnnotation = (function() {
|
||||||
init: init
|
init: init
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Closes the atwho popup * needed in repositories to close the popup
|
||||||
|
// if nothing is selected and the user leaves the form *
|
||||||
|
function closePopup() {
|
||||||
|
$('.atwho-header-res').find('.glyphicon-remove').click();
|
||||||
|
}
|
||||||
|
|
||||||
function initialize(field) {
|
function initialize(field) {
|
||||||
var atWho = new setAtWho(field);
|
var atWho = new setAtWho(field);
|
||||||
|
|
@ -432,7 +437,8 @@ var SmartAnnotation = (function() {
|
||||||
|
|
||||||
var publicApi = Object.freeze({
|
var publicApi = Object.freeze({
|
||||||
init: initialize,
|
init: initialize,
|
||||||
preventPropagation: atwhoStopPropagation
|
preventPropagation: atwhoStopPropagation,
|
||||||
|
closePopup: closePopup
|
||||||
});
|
});
|
||||||
|
|
||||||
return publicApi;
|
return publicApi;
|
||||||
|
|
|
||||||
|
|
@ -184,27 +184,27 @@ class RepositoriesController < ApplicationController
|
||||||
|
|
||||||
def parse_sheet
|
def parse_sheet
|
||||||
repository = current_team.repositories.find_by_id(params[:id])
|
repository = current_team.repositories.find_by_id(params[:id])
|
||||||
parsed_file = ImportRepository::ParseRepository.new(
|
|
||||||
file: params[:file],
|
|
||||||
repository: repository,
|
|
||||||
session: session
|
|
||||||
)
|
|
||||||
|
|
||||||
respond_to do |format|
|
unless params[:file]
|
||||||
unless params[:file]
|
repository_response(t('teams.parse_sheet.errors.no_file_selected'))
|
||||||
repository_response(t('teams.parse_sheet.errors.no_file_selected'))
|
return
|
||||||
return
|
end
|
||||||
end
|
begin
|
||||||
begin
|
parsed_file = ImportRepository::ParseRepository.new(
|
||||||
if parsed_file.too_large?
|
file: params[:file],
|
||||||
repository_response(t('general.file.size_exceeded',
|
repository: repository,
|
||||||
file_size: Constants::FILE_MAX_SIZE_MB))
|
session: session
|
||||||
elsif parsed_file.empty?
|
)
|
||||||
flash[:notice] = t('teams.parse_sheet.errors.empty_file')
|
if parsed_file.too_large?
|
||||||
redirect_to back and return
|
repository_response(t('general.file.size_exceeded',
|
||||||
else
|
file_size: Constants::FILE_MAX_SIZE_MB))
|
||||||
@import_data = parsed_file.data
|
elsif parsed_file.empty?
|
||||||
if parsed_file.generated_temp_file?
|
flash[:notice] = t('teams.parse_sheet.errors.empty_file')
|
||||||
|
redirect_to back and return
|
||||||
|
else
|
||||||
|
@import_data = parsed_file.data
|
||||||
|
if parsed_file.generated_temp_file?
|
||||||
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
render json: {
|
render json: {
|
||||||
html: render_to_string(
|
html: render_to_string(
|
||||||
|
|
@ -212,16 +212,16 @@ class RepositoriesController < ApplicationController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
else
|
|
||||||
repository_response(t('teams.parse_sheet.errors.temp_file_failure'))
|
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
repository_response(t('teams.parse_sheet.errors.temp_file_failure'))
|
||||||
end
|
end
|
||||||
rescue ArgumentError, CSV::MalformedCSVError
|
|
||||||
repository_response(t('teams.parse_sheet.errors.invalid_file',
|
|
||||||
encoding: ''.encoding))
|
|
||||||
rescue TypeError
|
|
||||||
repository_response(t('teams.parse_sheet.errors.invalid_extension'))
|
|
||||||
end
|
end
|
||||||
|
rescue ArgumentError, CSV::MalformedCSVError
|
||||||
|
repository_response(t('teams.parse_sheet.errors.invalid_file',
|
||||||
|
encoding: ''.encoding))
|
||||||
|
rescue TypeError
|
||||||
|
repository_response(t('teams.parse_sheet.errors.invalid_extension'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -238,8 +238,9 @@ class RepositoriesController < ApplicationController
|
||||||
number_of_rows: status[:nr_of_added])
|
number_of_rows: status[:nr_of_added])
|
||||||
render json: {}, status: :ok
|
render json: {}, status: :ok
|
||||||
else
|
else
|
||||||
flash[:alert] = t('repositories.import_records.error_flash',
|
flash[:alert] =
|
||||||
message: status[:errors])
|
t('repositories.import_records.partial_success_flash',
|
||||||
|
nr: status[:nr_of_added], total_nr: status[:total_nr])
|
||||||
render json: {}, status: :unprocessable_entity
|
render json: {}, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
@ -320,13 +321,15 @@ class RepositoriesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def repository_response(message)
|
def repository_response(message)
|
||||||
format.html do
|
respond_to do |format|
|
||||||
flash[:alert] = message
|
format.html do
|
||||||
redirect_to :back
|
flash[:alert] = message
|
||||||
end
|
redirect_to :back
|
||||||
format.json do
|
end
|
||||||
render json: { message: message },
|
format.json do
|
||||||
status: :unprocessable_entity
|
render json: { message: message },
|
||||||
|
status: :unprocessable_entity
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ class RepositoryRowsController < ApplicationController
|
||||||
|
|
||||||
record.transaction do
|
record.transaction do
|
||||||
record.name = record_params[:name] unless record_params[:name].blank?
|
record.name = record_params[:name] unless record_params[:name].blank?
|
||||||
unless record.save
|
errors[:default_fields] = record.errors.messages unless record.save
|
||||||
errors[:default_fields] = record.errors.messages
|
|
||||||
end
|
|
||||||
if params[:repository_cells]
|
if params[:repository_cells]
|
||||||
params[:repository_cells].each do |key, value|
|
params[:repository_cells].each do |key, value|
|
||||||
column = @repository.repository_columns.detect do |c|
|
column = @repository.repository_columns.detect do |c|
|
||||||
|
|
@ -94,9 +92,7 @@ class RepositoryRowsController < ApplicationController
|
||||||
|
|
||||||
@record.transaction do
|
@record.transaction do
|
||||||
@record.name = record_params[:name].blank? ? nil : record_params[:name]
|
@record.name = record_params[:name].blank? ? nil : record_params[:name]
|
||||||
unless @record.save
|
errors[:default_fields] = @record.errors.messages unless @record.save
|
||||||
errors[:default_fields] = @record.errors.messages
|
|
||||||
end
|
|
||||||
if params[:repository_cells]
|
if params[:repository_cells]
|
||||||
params[:repository_cells].each do |key, value|
|
params[:repository_cells].each do |key, value|
|
||||||
existing = @record.repository_cells.detect do |c|
|
existing = @record.repository_cells.detect do |c|
|
||||||
|
|
@ -119,7 +115,7 @@ class RepositoryRowsController < ApplicationController
|
||||||
column = @repository.repository_columns.detect do |c|
|
column = @repository.repository_columns.detect do |c|
|
||||||
c.id == key.to_i
|
c.id == key.to_i
|
||||||
end
|
end
|
||||||
value = RepositoryTextValue.new(
|
cell_value = RepositoryTextValue.new(
|
||||||
data: value,
|
data: value,
|
||||||
created_by: current_user,
|
created_by: current_user,
|
||||||
last_modified_by: current_user,
|
last_modified_by: current_user,
|
||||||
|
|
@ -128,15 +124,15 @@ class RepositoryRowsController < ApplicationController
|
||||||
repository_column: column
|
repository_column: column
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if value.save
|
if cell_value.save
|
||||||
record_annotation_notification(@record, value.repository_cell)
|
record_annotation_notification(@record,
|
||||||
|
cell_value.repository_cell)
|
||||||
else
|
else
|
||||||
errors[:repository_cells] << {
|
errors[:repository_cells] << {
|
||||||
"#{column.id}": value.errors.messages
|
"#{column.id}": cell_value.errors.messages
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
raise ActiveRecord::Rollback if errors[:repository_cells].any?
|
|
||||||
end
|
end
|
||||||
# Clean up empty cells, not present in updated record
|
# Clean up empty cells, not present in updated record
|
||||||
@record.repository_cells.each do |cell|
|
@record.repository_cells.each do |cell|
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ class TeamsController < ApplicationController
|
||||||
|
|
||||||
# Get data (it will trigger any errors as well)
|
# Get data (it will trigger any errors as well)
|
||||||
@header = sheet.row(1)
|
@header = sheet.row(1)
|
||||||
@rows = [];
|
@columns = sheet.row(2)
|
||||||
@rows << Hash[[@header, sheet.row(2)].transpose]
|
|
||||||
|
|
||||||
# Fill in fields for dropdown
|
# Fill in fields for dropdown
|
||||||
@available_fields = @team.get_available_sample_fields
|
@available_fields = @team.get_available_sample_fields
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,11 @@ class WopiController < ActionController::Base
|
||||||
UserCanNotWriteRelative: true,
|
UserCanNotWriteRelative: true,
|
||||||
CloseUrl: @close_url,
|
CloseUrl: @close_url,
|
||||||
DownloadUrl: url_for(controller: 'assets', action: 'download',
|
DownloadUrl: url_for(controller: 'assets', action: 'download',
|
||||||
id: @asset.id),
|
id: @asset.id, host: ENV['WOPI_USER_HOST']),
|
||||||
HostEditUrl: url_for(controller: 'assets', action: 'edit',
|
HostEditUrl: url_for(controller: 'assets', action: 'edit',
|
||||||
id: @asset.id),
|
id: @asset.id, host: ENV['WOPI_USER_HOST']),
|
||||||
HostViewUrl: url_for(controller: 'assets', action: 'view',
|
HostViewUrl: url_for(controller: 'assets', action: 'view',
|
||||||
id: @asset.id),
|
id: @asset.id, host: ENV['WOPI_USER_HOST']),
|
||||||
BreadcrumbBrandName: @breadcrumb_brand_name,
|
BreadcrumbBrandName: @breadcrumb_brand_name,
|
||||||
BreadcrumbBrandUrl: @breadcrumb_brand_url,
|
BreadcrumbBrandUrl: @breadcrumb_brand_url,
|
||||||
BreadcrumbFolderName: @breadcrumb_folder_name,
|
BreadcrumbFolderName: @breadcrumb_folder_name,
|
||||||
|
|
@ -82,7 +82,7 @@ class WopiController < ActionController::Base
|
||||||
}
|
}
|
||||||
response.headers['X-WOPI-HostEndpoint'] = ENV['WOPI_ENDPOINT_URL']
|
response.headers['X-WOPI-HostEndpoint'] = ENV['WOPI_ENDPOINT_URL']
|
||||||
response.headers['X-WOPI-MachineName'] = ENV['WOPI_ENDPOINT_URL']
|
response.headers['X-WOPI-MachineName'] = ENV['WOPI_ENDPOINT_URL']
|
||||||
response.headers['X-WOPI-ServerVersion'] = Constants::APP_VERSION
|
response.headers['X-WOPI-ServerVersion'] = Scinote::Application::VERSION
|
||||||
render json: msg and return
|
render json: msg and return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -286,21 +286,21 @@ class WopiController < ActionController::Base
|
||||||
if @protocol.in_module?
|
if @protocol.in_module?
|
||||||
@close_url = protocols_my_module_url(@protocol.my_module,
|
@close_url = protocols_my_module_url(@protocol.my_module,
|
||||||
only_path: false,
|
only_path: false,
|
||||||
host: ENV['WOPI_BREADCRUMBS_HOST'])
|
host: ENV['WOPI_USER_HOST'])
|
||||||
|
|
||||||
project = @protocol.my_module.experiment.project
|
project = @protocol.my_module.experiment.project
|
||||||
@breadcrumb_brand_name = project.name
|
@breadcrumb_brand_name = project.name
|
||||||
@breadcrumb_brand_url = project_url(project,
|
@breadcrumb_brand_url = project_url(project,
|
||||||
only_path: false,
|
only_path: false,
|
||||||
host: ENV['WOPI_BREADCRUMBS_HOST'])
|
host: ENV['WOPI_USER_HOST'])
|
||||||
@breadcrumb_folder_name = @protocol.my_module.name
|
@breadcrumb_folder_name = @protocol.my_module.name
|
||||||
else
|
else
|
||||||
@close_url = protocols_url(only_path: false,
|
@close_url = protocols_url(only_path: false,
|
||||||
host: ENV['WOPI_BREADCRUMBS_HOST'])
|
host: ENV['WOPI_USER_HOST'])
|
||||||
|
|
||||||
@breadcrump_brand_name = 'Projects'
|
@breadcrump_brand_name = 'Projects'
|
||||||
@breadcrumb_brand_url = root_url(only_path: false,
|
@breadcrumb_brand_url = root_url(only_path: false,
|
||||||
host: ENV['WOPI_BREADCRUMBS_HOST'])
|
host: ENV['WOPI_USER_HOST'])
|
||||||
@breadcrumb_folder_name = 'Protocol managament'
|
@breadcrumb_folder_name = 'Protocol managament'
|
||||||
end
|
end
|
||||||
@breadcrumb_folder_url = @close_url
|
@breadcrumb_folder_url = @close_url
|
||||||
|
|
@ -310,12 +310,12 @@ class WopiController < ActionController::Base
|
||||||
|
|
||||||
@close_url = results_my_module_url(@my_module,
|
@close_url = results_my_module_url(@my_module,
|
||||||
only_path: false,
|
only_path: false,
|
||||||
host: ENV['WOPI_BREADCRUMBS_HOST'])
|
host: ENV['WOPI_USER_HOST'])
|
||||||
|
|
||||||
@breadcrumb_brand_name = @my_module.experiment.project.name
|
@breadcrumb_brand_name = @my_module.experiment.project.name
|
||||||
@breadcrumb_brand_url = project_url(@my_module.experiment.project,
|
@breadcrumb_brand_url = project_url(@my_module.experiment.project,
|
||||||
only_path: false,
|
only_path: false,
|
||||||
host: ENV['WOPI_BREADCRUMBS_HOST'])
|
host: ENV['WOPI_USER_HOST'])
|
||||||
@breadcrumb_folder_name = @my_module.name
|
@breadcrumb_folder_name = @my_module.name
|
||||||
@breadcrumb_folder_url = @close_url
|
@breadcrumb_folder_url = @close_url
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ class RepositoryDatatable < CustomDatatable
|
||||||
# Make mappings of custom columns, so we have same id for every column
|
# Make mappings of custom columns, so we have same id for every column
|
||||||
i = 5
|
i = 5
|
||||||
@columns_mappings = {}
|
@columns_mappings = {}
|
||||||
@repository.repository_columns.each do |column|
|
@repository.repository_columns.order(:id).each do |column|
|
||||||
@columns_mappings[column.id] = i.to_s
|
@columns_mappings[column.id] = i.to_s
|
||||||
i += 1
|
i += 1
|
||||||
end
|
end
|
||||||
|
|
@ -230,13 +230,68 @@ class RepositoryDatatable < CustomDatatable
|
||||||
|
|
||||||
# Override default sort method if needed
|
# Override default sort method if needed
|
||||||
def sort_records(records)
|
def sort_records(records)
|
||||||
if sort_column(order_params) == ASSIGNED_SORT_COL
|
if params[:order].present? && params[:order].length == 1
|
||||||
# If "assigned" column is sorted
|
if sort_column(params[:order].values[0]) == ASSIGNED_SORT_COL
|
||||||
direction = sort_null_direction(order_params)
|
# If "assigned" column is sorted when viewing assigned items
|
||||||
if @my_module
|
return records if @my_module && params[:assigned] == 'assigned'
|
||||||
# Depending on the sort, order nulls first or
|
# If "assigned" column is sorted
|
||||||
# nulls last on repository_cells association
|
direction = sort_null_direction(params[:order].values[0])
|
||||||
return records if dt_params[:assigned] == 'assigned'
|
if @my_module
|
||||||
|
# Depending on the sort, order nulls first or
|
||||||
|
# nulls last on repository_cells association
|
||||||
|
records.joins(
|
||||||
|
"LEFT OUTER JOIN my_module_repository_rows ON
|
||||||
|
(repository_rows.id = my_module_repository_rows.repository_row_id
|
||||||
|
AND (my_module_repository_rows.my_module_id = #{@my_module.id} OR
|
||||||
|
my_module_repository_rows.id IS NULL))"
|
||||||
|
).order("my_module_repository_rows.id NULLS #{direction}")
|
||||||
|
else
|
||||||
|
sort_assigned_records(records, params[:order].values[0]['dir'])
|
||||||
|
end
|
||||||
|
elsif sorting_by_custom_column
|
||||||
|
# Check if have to filter records first
|
||||||
|
# if params[:search].present? && params[:search][:value].present?
|
||||||
|
# # Couldn't force ActiveRecord to yield the same query as below because
|
||||||
|
# # Rails apparently forgets to join stuff in subqueries -
|
||||||
|
# # #justrailsthings
|
||||||
|
# conditions = build_conditions_for(params[:search][:value])
|
||||||
|
#
|
||||||
|
# filter_query = %(SELECT "samples"."id" FROM "samples"
|
||||||
|
# LEFT OUTER JOIN "sample_custom_fields" ON
|
||||||
|
# "sample_custom_fields"."sample_id" = "samples"."id"
|
||||||
|
# LEFT OUTER JOIN "users" ON "users"."id" = "repository_row"."user_id"
|
||||||
|
# WHERE "samples"."team_id" = #{@team.id} AND #{conditions.to_sql})
|
||||||
|
#
|
||||||
|
# records = records.where("samples.id IN (#{filter_query})")
|
||||||
|
# end
|
||||||
|
|
||||||
|
ci = sortable_displayed_columns[
|
||||||
|
params[:order].values[0][:column].to_i - 1
|
||||||
|
]
|
||||||
|
column_id = @columns_mappings.key((ci.to_i + 1).to_s)
|
||||||
|
dir = sort_direction(params[:order].values[0])
|
||||||
|
|
||||||
|
# Because repository records can have multiple custom cells,
|
||||||
|
# we first group them by samples.id and inside that group we sort them by column_id. Because
|
||||||
|
# we sort them ASC, sorted columns will be on top. Distinct then only
|
||||||
|
# takes the first row and cuts the rest of every group and voila we have
|
||||||
|
# 1 row for every sample, which are not sorted yet ...
|
||||||
|
# records = records.select('DISTINCT ON (repository_rows.id) *')
|
||||||
|
# .order("repository_rows.id, CASE WHEN repository_cells.repository_column_id = #{column_id} THEN 1 ELSE 2 END ASC")
|
||||||
|
|
||||||
|
# ... this little gem (pun intended) then takes the records query, sorts it again
|
||||||
|
# and paginates it. sq.t0_* are determined empirically and are crucial -
|
||||||
|
# imagine A -> B -> C transitive relation but where A and C are the
|
||||||
|
# same. Useless right? But not when you acknowledge that find_by_sql
|
||||||
|
# method does some funky stuff when your query spans multiple queries -
|
||||||
|
# Sample object might have id from SampleType, name from
|
||||||
|
# User ... chaos ensues basically. If something changes in db this might
|
||||||
|
# change.
|
||||||
|
# formated_date = (I18n.t 'time.formats.datatables_date').gsub!(/^\"|\"?$/, '')
|
||||||
|
# Sample.find_by_sql("SELECT sq.t0_r0 as id, sq.t0_r1 as name, to_char( sq.t0_r4, '#{ formated_date }' ) as created_at, sq.t0_r5, s, sq.t0_r2 as user_id, sq.custom_field_id FROM (#{records.to_sql})
|
||||||
|
# as sq ORDER BY CASE WHEN sq.custom_field_id = #{column_id} THEN 1 ELSE 2 END #{dir}, sq.value #{dir}
|
||||||
|
# LIMIT #{per_page} OFFSET #{offset}")
|
||||||
|
|
||||||
records.joins(
|
records.joins(
|
||||||
"LEFT OUTER JOIN my_module_repository_rows ON
|
"LEFT OUTER JOIN my_module_repository_rows ON
|
||||||
(repository_rows.id = my_module_repository_rows.repository_row_id
|
(repository_rows.id = my_module_repository_rows.repository_row_id
|
||||||
|
|
@ -307,4 +362,21 @@ class RepositoryDatatable < CustomDatatable
|
||||||
|
|
||||||
@sortable_displayed_columns = sort_order
|
@sortable_displayed_columns = sort_order
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sort_assigned_records(records, direction)
|
||||||
|
assigned = records.joins(:my_module_repository_rows).distinct.pluck(:id)
|
||||||
|
unassigned = records.where.not(id: assigned).pluck(:id)
|
||||||
|
if direction == 'asc'
|
||||||
|
ids = assigned + unassigned
|
||||||
|
elsif direction == 'desc'
|
||||||
|
ids = unassigned + assigned
|
||||||
|
end
|
||||||
|
|
||||||
|
order_by_index = ActiveRecord::Base.send(
|
||||||
|
:sanitize_sql_array,
|
||||||
|
["position((',' || repository_rows.id || ',') in ?)",
|
||||||
|
ids.join(',') + ',']
|
||||||
|
)
|
||||||
|
records.order(order_by_index)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
8
app/helpers/addons_helper.rb
Normal file
8
app/helpers/addons_helper.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
module AddonsHelper
|
||||||
|
def list_all_addons
|
||||||
|
Rails::Engine
|
||||||
|
.subclasses
|
||||||
|
.select { |c| c.name.start_with?('Scinote') }
|
||||||
|
.map(&:parent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1075,11 +1075,13 @@ module PermissionHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_delete_column_in_repository(column)
|
def can_delete_column_in_repository(column)
|
||||||
is_normal_user_or_admin_of_team(column.repository.team)
|
column.created_by == current_user ||
|
||||||
|
is_admin_of_team(column.repository.team)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_edit_column_in_repository(column)
|
def can_edit_column_in_repository(column)
|
||||||
is_normal_user_or_admin_of_team(column.repository.team)
|
column.created_by == current_user ||
|
||||||
|
is_admin_of_team(column.repository.team)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_create_repository_records(repository)
|
def can_create_repository_records(repository)
|
||||||
|
|
|
||||||
|
|
@ -384,10 +384,17 @@ class Asset < ApplicationRecord
|
||||||
action = get_action(file_ext, action)
|
action = get_action(file_ext, action)
|
||||||
if !action.nil?
|
if !action.nil?
|
||||||
action_url = action.urlsrc
|
action_url = action.urlsrc
|
||||||
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER&>/,
|
if ENV['WOPI_BUSINESS_USERS'] && ENV['WOPI_BUSINESS_USERS']=='true'
|
||||||
'IsLicensedUser=0&')
|
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER&>/,
|
||||||
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER>/,
|
'IsLicensedUser=1&')
|
||||||
'IsLicensedUser=0')
|
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER>/,
|
||||||
|
'IsLicensedUser=1')
|
||||||
|
else
|
||||||
|
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER&>/,
|
||||||
|
'IsLicensedUser=0&')
|
||||||
|
action_url = action_url.gsub(/<IsLicensedUser=BUSINESS_USER>/,
|
||||||
|
'IsLicensedUser=0')
|
||||||
|
end
|
||||||
action_url = action_url.gsub(/<.*?=.*?>/, '')
|
action_url = action_url.gsub(/<.*?=.*?>/, '')
|
||||||
|
|
||||||
rest_url = Rails.application.routes.url_helpers.wopi_rest_endpoint_url(
|
rest_url = Rails.application.routes.url_helpers.wopi_rest_endpoint_url(
|
||||||
|
|
|
||||||
|
|
@ -111,57 +111,82 @@ class Repository < ApplicationRecord
|
||||||
|
|
||||||
# Imports records
|
# Imports records
|
||||||
def import_records(sheet, mappings, user)
|
def import_records(sheet, mappings, user)
|
||||||
errors = []
|
errors = false
|
||||||
custom_fields = []
|
columns = []
|
||||||
name_index = -1
|
name_index = -1
|
||||||
|
total_nr = 0
|
||||||
nr_of_added = 0
|
nr_of_added = 0
|
||||||
|
|
||||||
mappings.each.with_index do |(_k, value), index|
|
mappings.each.with_index do |(_k, value), index|
|
||||||
if value == '-1'
|
if value == '-1'
|
||||||
# Fill blank space, so our indices stay the same
|
# Fill blank space, so our indices stay the same
|
||||||
custom_fields << nil
|
columns << nil
|
||||||
name_index = index
|
name_index = index
|
||||||
else
|
else
|
||||||
cf = repository_columns.find_by_id(value)
|
columns << repository_columns.find_by_id(value)
|
||||||
custom_fields << cf
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Check for duplicate columns
|
||||||
|
col_compact = columns.compact
|
||||||
|
unless col_compact.map(&:id).uniq.length == col_compact.length
|
||||||
|
return { status: :error, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||||
|
end
|
||||||
|
|
||||||
# Now we can iterate through record data and save stuff into db
|
# Now we can iterate through record data and save stuff into db
|
||||||
(2..sheet.last_row).each do |i|
|
transaction do
|
||||||
error = []
|
(2..sheet.last_row).each do |i|
|
||||||
record_row = RepositoryRow.new(name: sheet.row(i)[name_index],
|
total_nr += 1
|
||||||
repository: self,
|
record_row = RepositoryRow.new(name: sheet.row(i)[name_index],
|
||||||
created_by: user,
|
repository: self,
|
||||||
last_modified_by: user)
|
created_by: user,
|
||||||
|
last_modified_by: user)
|
||||||
|
record_row.transaction(requires_new: true) do
|
||||||
|
unless record_row.save
|
||||||
|
errors = true
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
end
|
||||||
|
|
||||||
next unless record_row.valid?
|
row_cell_values = []
|
||||||
sheet.row(i).each.with_index do |value, index|
|
|
||||||
if custom_fields[index] && value
|
sheet.row(i).each.with_index do |value, index|
|
||||||
rep_column = RepositoryTextValue.new(
|
if columns[index] && value
|
||||||
data: value,
|
cell_value = RepositoryTextValue.new(
|
||||||
created_by: user,
|
data: value,
|
||||||
last_modified_by: user,
|
created_by: user,
|
||||||
repository_cell_attributes: {
|
last_modified_by: user,
|
||||||
repository_row: record_row,
|
repository_cell_attributes: {
|
||||||
repository_column: custom_fields[index]
|
repository_row: record_row,
|
||||||
}
|
repository_column: columns[index]
|
||||||
)
|
}
|
||||||
error << rep_column.errors.messages unless rep_column.save
|
)
|
||||||
|
cell = RepositoryCell.new(repository_row: record_row,
|
||||||
|
repository_column: columns[index],
|
||||||
|
value: cell_value)
|
||||||
|
cell.skip_on_import = true
|
||||||
|
cell_value.repository_cell = cell
|
||||||
|
unless cell.valid? && cell_value.valid?
|
||||||
|
errors = true
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
end
|
||||||
|
row_cell_values << cell_value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if RepositoryTextValue.import(row_cell_values,
|
||||||
|
recursive: true,
|
||||||
|
validate: false).failed_instances.any?
|
||||||
|
errors = true
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
end
|
||||||
|
nr_of_added += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if error.any?
|
|
||||||
record_row.destroy
|
|
||||||
else
|
|
||||||
nr_of_added += 1
|
|
||||||
record_row.save
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if errors.count > 0
|
if errors
|
||||||
return { status: :error, errors: errors, nr_of_added: nr_of_added }
|
return { status: :error, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||||
end
|
end
|
||||||
{ status: :ok, nr_of_added: nr_of_added }
|
{ status: :ok, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -170,13 +195,11 @@ class Repository < ApplicationRecord
|
||||||
case File.extname(filename)
|
case File.extname(filename)
|
||||||
when '.csv'
|
when '.csv'
|
||||||
Roo::CSV.new(file_path, extension: :csv)
|
Roo::CSV.new(file_path, extension: :csv)
|
||||||
when '.tdv'
|
when '.tsv'
|
||||||
Roo::CSV.new(file_path, nil, :ignore, csv_options: { col_sep: '\t' })
|
Roo::CSV.new(file_path, csv_options: { col_sep: "\t" })
|
||||||
when '.txt'
|
when '.txt'
|
||||||
# This assumption is based purely on biologist's habits
|
# This assumption is based purely on biologist's habits
|
||||||
Roo::CSV.new(file_path, csv_options: { col_sep: '\t' })
|
Roo::CSV.new(file_path, csv_options: { col_sep: "\t" })
|
||||||
when '.xls'
|
|
||||||
Roo::Excel.new(file_path)
|
|
||||||
when '.xlsx'
|
when '.xlsx'
|
||||||
Roo::Excelx.new(file_path)
|
Roo::Excelx.new(file_path)
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
class RepositoryCell < ApplicationRecord
|
class RepositoryCell < ActiveRecord::Base
|
||||||
belongs_to :repository_row, optional: true
|
attr_accessor :skip_on_import
|
||||||
belongs_to :repository_column, optional: true
|
|
||||||
belongs_to :value, polymorphic: true, dependent: :destroy, optional: true
|
belongs_to :repository_row
|
||||||
|
belongs_to :repository_column
|
||||||
|
belongs_to :value, polymorphic: true, dependent: :destroy
|
||||||
|
|
||||||
validates :repository_column, presence: true
|
validates :repository_column, presence: true
|
||||||
validate :repository_column_data_type
|
validate :repository_column_data_type
|
||||||
validates :repository_row, uniqueness: { scope: :repository_column }
|
validates :repository_row,
|
||||||
|
uniqueness: { scope: :repository_column },
|
||||||
|
unless: :skip_on_import
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,16 +43,14 @@ class Team < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
case File.extname(filename)
|
case File.extname(filename)
|
||||||
when ".csv" then
|
when '.csv' then
|
||||||
Roo::CSV.new(file_path, extension: :csv)
|
Roo::CSV.new(file_path, extension: :csv)
|
||||||
when ".tdv" then
|
when '.tsv' then
|
||||||
Roo::CSV.new(file_path, nil, :ignore, csv_options: {col_sep: "\t"})
|
Roo::CSV.new(file_path, csv_options: { col_sep: "\t" })
|
||||||
when ".txt" then
|
when '.txt' then
|
||||||
# This assumption is based purely on biologist's habits
|
# This assumption is based purely on biologist's habits
|
||||||
Roo::CSV.new(file_path, csv_options: {col_sep: "\t"})
|
Roo::CSV.new(file_path, csv_options: { col_sep: "\t" })
|
||||||
when ".xls" then
|
when '.xlsx' then
|
||||||
Roo::Excel.new(file_path)
|
|
||||||
when ".xlsx" then
|
|
||||||
Roo::Excelx.new(file_path)
|
Roo::Excelx.new(file_path)
|
||||||
else
|
else
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
@ -71,7 +69,7 @@ class Team < ApplicationRecord
|
||||||
# -3 == sample_group
|
# -3 == sample_group
|
||||||
# TODO: use constants
|
# TODO: use constants
|
||||||
def import_samples(sheet, mappings, user)
|
def import_samples(sheet, mappings, user)
|
||||||
errors = []
|
errors = false
|
||||||
nr_of_added = 0
|
nr_of_added = 0
|
||||||
total_nr = 0
|
total_nr = 0
|
||||||
|
|
||||||
|
|
@ -80,17 +78,17 @@ class Team < ApplicationRecord
|
||||||
sname_index = -1
|
sname_index = -1
|
||||||
stype_index = -1
|
stype_index = -1
|
||||||
sgroup_index = -1
|
sgroup_index = -1
|
||||||
mappings.each.with_index do |(k, v), i|
|
mappings.each.with_index do |(_, v), i|
|
||||||
if v == "-1"
|
if v == '-1'
|
||||||
# Fill blank space, so our indices stay the same
|
# Fill blank space, so our indices stay the same
|
||||||
custom_fields << nil
|
custom_fields << nil
|
||||||
sname_index = i
|
sname_index = i
|
||||||
elsif v == "-2"
|
elsif v == '-2'
|
||||||
custom_fields << nil
|
custom_fields << nil
|
||||||
stype_index = i
|
stype_index = i
|
||||||
elsif v == "-3"
|
elsif v == '-3'
|
||||||
custom_fields << nil
|
custom_fields << nil
|
||||||
sgroup_index = i
|
sgroup_index = i
|
||||||
else
|
else
|
||||||
cf = CustomField.find_by_id(v)
|
cf = CustomField.find_by_id(v)
|
||||||
|
|
||||||
|
|
@ -99,87 +97,70 @@ class Team < ApplicationRecord
|
||||||
custom_fields << cf
|
custom_fields << cf
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Now we can iterate through sample data and save stuff into db
|
# Now we can iterate through sample data and save stuff into db
|
||||||
(2..sheet.last_row).each do |i|
|
(2..sheet.last_row).each do |i|
|
||||||
error = []
|
|
||||||
total_nr += 1
|
total_nr += 1
|
||||||
|
sample = Sample.new(name: sheet.row(i)[sname_index],
|
||||||
|
team: self,
|
||||||
|
user: user)
|
||||||
|
|
||||||
sample = Sample.new(
|
sample.transaction do
|
||||||
name: sheet.row(i)[sname_index],
|
unless sample.valid?
|
||||||
team_id: id,
|
errors = true
|
||||||
user: user
|
raise ActiveRecord::Rollback
|
||||||
)
|
end
|
||||||
|
|
||||||
if sample.save
|
|
||||||
sheet.row(i).each.with_index do |value, index|
|
sheet.row(i).each.with_index do |value, index|
|
||||||
# We need to have sample saved before messing with custom fields (they
|
|
||||||
# need sample id)
|
|
||||||
if index == stype_index
|
if index == stype_index
|
||||||
stype = SampleType.where(name: value, team_id: id).take
|
stype = SampleType.where(name: value, team: self).take
|
||||||
|
|
||||||
if stype
|
unless stype
|
||||||
sample.sample_type = stype
|
stype = SampleType.new(name: value, team: self)
|
||||||
else
|
unless stype.save
|
||||||
sample.create_sample_type(
|
errors = true
|
||||||
name: value,
|
raise ActiveRecord::Rollback
|
||||||
team_id: id
|
|
||||||
)
|
|
||||||
end
|
|
||||||
sample.save
|
|
||||||
elsif index == sgroup_index
|
|
||||||
sgroup = SampleGroup.where(name: value, team_id: id).take
|
|
||||||
|
|
||||||
if sgroup
|
|
||||||
sample.sample_group = sgroup
|
|
||||||
else
|
|
||||||
sample.create_sample_group(
|
|
||||||
name: value,
|
|
||||||
team_id: id
|
|
||||||
)
|
|
||||||
end
|
|
||||||
sample.save
|
|
||||||
elsif value and mappings[index.to_s].strip.present? and index != sname_index
|
|
||||||
if custom_fields[index]
|
|
||||||
# we're working with CustomField
|
|
||||||
scf = SampleCustomField.new(
|
|
||||||
sample_id: sample.id,
|
|
||||||
custom_field_id: custom_fields[index].id,
|
|
||||||
value: value
|
|
||||||
)
|
|
||||||
|
|
||||||
if !scf.save
|
|
||||||
error << scf.errors.messages
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
# This custom_field does not exist
|
|
||||||
error << {"#{mappings[index]}": "Does not exists"}
|
|
||||||
end
|
end
|
||||||
|
sample.sample_type = stype
|
||||||
|
elsif index == sgroup_index
|
||||||
|
sgroup = SampleGroup.where(name: value, team: self).take
|
||||||
|
|
||||||
|
unless sgroup
|
||||||
|
sgroup = SampleGroup.new(name: value, team: self)
|
||||||
|
unless sgroup.save
|
||||||
|
errors = true
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
end
|
||||||
|
end
|
||||||
|
sample.sample_group = sgroup
|
||||||
|
elsif value && custom_fields[index]
|
||||||
|
# we're working with CustomField
|
||||||
|
scf = SampleCustomField.new(
|
||||||
|
sample: sample,
|
||||||
|
custom_field: custom_fields[index],
|
||||||
|
value: value
|
||||||
|
)
|
||||||
|
unless scf.valid?
|
||||||
|
errors = true
|
||||||
|
raise ActiveRecord::Rollback
|
||||||
|
end
|
||||||
|
sample.sample_custom_fields << scf
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
if Sample.import([sample],
|
||||||
error << sample.errors.messages
|
recursive: true,
|
||||||
end
|
validate: false).failed_instances.any?
|
||||||
if error.present?
|
errors = true
|
||||||
errors << { "#{i}": error}
|
raise ActiveRecord::Rollback
|
||||||
else
|
end
|
||||||
nr_of_added += 1
|
nr_of_added += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if errors.count > 0 then
|
if errors
|
||||||
return {
|
return { status: :error, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||||
status: :error,
|
|
||||||
errors: errors,
|
|
||||||
nr_of_added: nr_of_added,
|
|
||||||
total_nr: total_nr
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return {
|
return { status: :ok, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||||
status: :ok,
|
|
||||||
nr_of_added: nr_of_added,
|
|
||||||
total_nr: total_nr
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,14 @@ module ImportRepository
|
||||||
def data
|
def data
|
||||||
# Get data (it will trigger any errors as well)
|
# Get data (it will trigger any errors as well)
|
||||||
header = @sheet.row(1)
|
header = @sheet.row(1)
|
||||||
rows = []
|
columns = @sheet.row(2)
|
||||||
rows << Hash[[header, @sheet.row(2)].transpose]
|
|
||||||
# Fill in fields for dropdown
|
# Fill in fields for dropdown
|
||||||
@repository.available_repository_fields.transform_values! do |name|
|
@repository.available_repository_fields.transform_values! do |name|
|
||||||
truncate(name, length: Constants::NAME_TRUNCATION_LENGTH_DROPDOWN)
|
truncate(name, length: Constants::NAME_TRUNCATION_LENGTH_DROPDOWN)
|
||||||
end
|
end
|
||||||
@temp_file = TempFile.create(session_id: @session.id, file: @file)
|
@temp_file = TempFile.create(session_id: @session.id, file: @file)
|
||||||
Data.new(header,
|
Data.new(header,
|
||||||
rows,
|
columns,
|
||||||
@repository.available_repository_fields,
|
@repository.available_repository_fields,
|
||||||
@repository,
|
@repository,
|
||||||
@temp_file)
|
@temp_file)
|
||||||
|
|
@ -47,7 +46,7 @@ module ImportRepository
|
||||||
end
|
end
|
||||||
|
|
||||||
Data = Struct.new(
|
Data = Struct.new(
|
||||||
:header, :rows, :available_fields, :repository, :temp_file
|
:header, :columns, :available_fields, :repository, :temp_file
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- About us modal -->
|
||||||
|
<%= render "shared/about_modal" %>
|
||||||
|
|
||||||
<%= render "shared/navigation" %>
|
<%= render "shared/navigation" %>
|
||||||
|
|
||||||
<div id="notifications">
|
<div id="notifications">
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="content">
|
<div id="content"
|
||||||
|
data-repo-id="#repository-table-<%= @repository.id %>">
|
||||||
<%= render partial: "repositories/repository_table",
|
<%= render partial: "repositories/repository_table",
|
||||||
locals: {
|
locals: {
|
||||||
repository: @repository,
|
repository: @repository,
|
||||||
|
|
@ -40,3 +41,7 @@
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<%= stylesheet_link_tag 'datatables' %>
|
||||||
|
<%= javascript_include_tag 'repositories/repository_datatable' %>
|
||||||
|
<%= javascript_include_tag 'repositories/my_module_repository' %>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="modal fade"
|
<div class="modal fade"
|
||||||
id="parse-records_modal"
|
id="parse-records-modal"
|
||||||
aria-labelledby="parse-modal-title"
|
aria-labelledby="parse-modal-title"
|
||||||
role="dialog">
|
role="dialog">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
|
|
@ -30,29 +30,31 @@
|
||||||
include_blank: t('teams.parse_sheet.do_not_include_column'),
|
include_blank: t('teams.parse_sheet.do_not_include_column'),
|
||||||
hide_label: true) %>
|
hide_label: true) %>
|
||||||
<br />
|
<br />
|
||||||
<% if th.length > Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>
|
<% if th.nil? %>
|
||||||
<div class="modal-tooltip">
|
<i><%= t('repositories.import_records.no_header_name') %></i>
|
||||||
<%= truncate(th, length: Constants::NAME_TRUNCATION_LENGTH_DROPDOWN) %>
|
|
||||||
</div>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= th %>
|
<% if th.length > Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>
|
||||||
|
<div class="modal-tooltip">
|
||||||
|
<%= truncate(th, length: Constants::NAME_TRUNCATION_LENGTH_DROPDOWN) %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<%= th %>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</th>
|
</th>
|
||||||
<% end %>
|
<% end %>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% @import_data.rows.each do |row| %>
|
<tr>
|
||||||
<tr>
|
<td>
|
||||||
|
<p><%= t('teams.parse_sheet.example_value') %></p>
|
||||||
|
</td>
|
||||||
|
<% @import_data.columns.each do |td| %>
|
||||||
<td>
|
<td>
|
||||||
<p><%= t('teams.parse_sheet.example_value') %></p>
|
<%= td %>
|
||||||
</td>
|
</td>
|
||||||
<% row.each do |td| %>
|
<% end %>
|
||||||
<td>
|
</tr>
|
||||||
<%= td[1] %>
|
|
||||||
</td>
|
|
||||||
<% end %>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="repository-table">
|
<div class="repository-table">
|
||||||
<table id="repository-table" class="table"
|
<table id="repository-table-<%= repository.id %>" class="table"
|
||||||
data-current-uri="<%= request.original_url %>"
|
data-current-uri="<%= request.original_url %>"
|
||||||
data-repository-id="<%= repository.id %>"
|
data-repository-id="<%= repository.id %>"
|
||||||
data-source="<%= repository_index_link %>"
|
data-source="<%= repository_index_link %>"
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<th id="row-name"><%= t("repositories.table.row_name") %></th>
|
<th id="row-name"><%= t("repositories.table.row_name") %></th>
|
||||||
<th id="added-on"><%= t("repositories.table.added_on") %></th>
|
<th id="added-on"><%= t("repositories.table.added_on") %></th>
|
||||||
<th id="added-by"><%= t("repositories.table.added_by") %></th>
|
<th id="added-by"><%= t("repositories.table.added_by") %></th>
|
||||||
<% repository.repository_columns.each do |column| %>
|
<% repository.repository_columns.order(:id).each do |column| %>
|
||||||
<th class="repository-column" id="<%= column.id %>"
|
<th class="repository-column" id="<%= column.id %>"
|
||||||
<%= 'data-editable' if can_edit_column_in_repository(column) %>
|
<%= 'data-editable' if can_edit_column_in_repository(column) %>
|
||||||
<%= 'data-deletable' if can_delete_column_in_repository(column) %>
|
<%= 'data-deletable' if can_delete_column_in_repository(column) %>
|
||||||
|
|
@ -35,6 +35,3 @@
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= stylesheet_link_tag 'datatables' %>
|
|
||||||
<%= javascript_include_tag('repositories/repository_datatable') %>
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a href="#custom_repo_<%= repo.id %>"
|
<a href="#custom_repo_<%= repo.id %>"
|
||||||
data-toggle="tab"
|
data-toggle="tab"
|
||||||
|
data-repo-table="#repository-table-<%= repo.id %>"
|
||||||
aria-controls="custom_repo_<%= repo.id %>"
|
aria-controls="custom_repo_<%= repo.id %>"
|
||||||
data-url="<%=team_repository_show_tab_path(current_team, repo)%>"
|
data-url="<%=team_repository_show_tab_path(current_team, repo)%>"
|
||||||
title="<%=repo.name%>"><%= truncate(repo.name, length: Constants::NAME_TRUNCATION_LENGTH) %></a>
|
title="<%=repo.name%>"><%= truncate(repo.name, length: Constants::NAME_TRUNCATION_LENGTH) %></a>
|
||||||
|
|
@ -53,4 +54,6 @@
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<%= stylesheet_link_tag 'datatables' %>
|
||||||
|
<%= javascript_include_tag 'repositories/repository_datatable' %>
|
||||||
<%= javascript_include_tag "repositories/index", "data-turbolinks-track" => true %>
|
<%= javascript_include_tag "repositories/index", "data-turbolinks-track" => true %>
|
||||||
|
|
|
||||||
|
|
@ -25,29 +25,31 @@
|
||||||
include_blank: t('teams.parse_sheet.do_not_include_column'),
|
include_blank: t('teams.parse_sheet.do_not_include_column'),
|
||||||
hide_label: true) %>
|
hide_label: true) %>
|
||||||
<br />
|
<br />
|
||||||
<% if th.length > Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>
|
<% if th.nil? %>
|
||||||
<div class="modal-tooltip">
|
<i><%= t('samples.modal_import.no_header_name') %></i>
|
||||||
<%= truncate(th, length: Constants::NAME_TRUNCATION_LENGTH_DROPDOWN) %>
|
|
||||||
</div>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= th %>
|
<% if th.length > Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>
|
||||||
|
<div class="modal-tooltip">
|
||||||
|
<%= truncate(th, length: Constants::NAME_TRUNCATION_LENGTH_DROPDOWN) %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<%= th %>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</th>
|
</th>
|
||||||
<% end %>
|
<% end %>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% @rows.each do |row| %>
|
<tr>
|
||||||
<tr>
|
<td>
|
||||||
|
<p><%= t('teams.parse_sheet.example_value') %></p>
|
||||||
|
</td>
|
||||||
|
<% @columns.each do |td| %>
|
||||||
<td>
|
<td>
|
||||||
<p><%= t('teams.parse_sheet.example_value') %></p>
|
<%= td %>
|
||||||
</td>
|
</td>
|
||||||
<% row.each do |td| %>
|
<% end %>
|
||||||
<td>
|
</tr>
|
||||||
<%= td[1] %>
|
|
||||||
</td>
|
|
||||||
<% end %>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
28
app/views/shared/_about_modal.html.erb
Normal file
28
app/views/shared/_about_modal.html.erb
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<div class="modal" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="aboutModal" data-role="about-modal">
|
||||||
|
<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">×</span></button>
|
||||||
|
<h4 class="modal-title"><%= t('about.modal_title') %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<strong><%= t('about.core_version') %></strong>
|
||||||
|
<br />
|
||||||
|
<%= Scinote::Application::VERSION %>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div data-hook="about-modal-addon-versions">
|
||||||
|
<strong><%= t('about.addon_versions') %></strong>
|
||||||
|
<br />
|
||||||
|
<% list_all_addons.each do |addon| %>
|
||||||
|
<%= "#{addon.name}:" %>
|
||||||
|
<br />
|
||||||
|
<%= addon::VERSION %>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<% if show_version %>
|
<% if show_version %>
|
||||||
<%= image_tag('/images/logo.png', class: 'with-version', id: 'logo') %>
|
<%= image_tag('/images/logo.png', class: 'with-version', id: 'logo') %>
|
||||||
<span class="version">
|
<span class="version">
|
||||||
<%= Constants::APP_VERSION %>
|
<%= Scinote::Application::VERSION %>
|
||||||
</span>
|
</span>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= image_tag('/images/logo.png', id: 'logo') %>
|
<%= image_tag('/images/logo.png', id: 'logo') %>
|
||||||
|
|
@ -234,6 +234,12 @@
|
||||||
<li><%= link_to t('nav.help.contact'),
|
<li><%= link_to t('nav.help.contact'),
|
||||||
Constants::CONTACT_URL,
|
Constants::CONTACT_URL,
|
||||||
target: "_blank" %></li>
|
target: "_blank" %></li>
|
||||||
|
<li role="separator" class="divider"></li>
|
||||||
|
<li>
|
||||||
|
<%= link_to '#', data: { trigger: 'about-modal' } do %>
|
||||||
|
<%= t('nav.help.about') %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,10 @@
|
||||||
<ul class="dropdown-menu repositories-dropdown-menu" aria-labelledby="repositoriesDropdownMenuLink">
|
<ul class="dropdown-menu repositories-dropdown-menu" aria-labelledby="repositoriesDropdownMenuLink">
|
||||||
<% @my_module.experiment.project.team.repositories.order(created_at: :asc).each do |repository| %>
|
<% @my_module.experiment.project.team.repositories.order(created_at: :asc).each do |repository| %>
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="<%= repository_my_module_url(id: @my_module, repository_id: repository) %>" title="<%= repository.name %>">
|
<a class="dropdown-item"
|
||||||
|
href="<%= repository_my_module_url(id: @my_module, repository_id: repository) %>"
|
||||||
|
title="<%= repository.name %>"
|
||||||
|
data-no-turbolink="true">
|
||||||
<%= truncate(repository.name) %>
|
<%= truncate(repository.name) %>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -29,5 +29,8 @@ module Scinote
|
||||||
csv: 'text/plain',
|
csv: 'text/plain',
|
||||||
wopitest: ['text/plain', 'inode/x-empty']
|
wopitest: ['text/plain', 'inode/x-empty']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# sciNote Core Application version
|
||||||
|
VERSION = File.read(Rails.root.join('VERSION')).strip.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ Rails.application.config.assets.precompile += %w(repositories/index.js)
|
||||||
Rails.application.config.assets.precompile += %w(repositories/edit.js)
|
Rails.application.config.assets.precompile += %w(repositories/edit.js)
|
||||||
Rails.application.config.assets.precompile +=
|
Rails.application.config.assets.precompile +=
|
||||||
%w(repositories/repository_datatable.js)
|
%w(repositories/repository_datatable.js)
|
||||||
|
Rails.application.config.assets.precompile +=
|
||||||
|
%w(repositories/my_module_repository.js)
|
||||||
|
|
||||||
# Libraries needed for Handsontable formulas
|
# Libraries needed for Handsontable formulas
|
||||||
Rails.application.config.assets.precompile += %w(lodash.js)
|
Rails.application.config.assets.precompile += %w(lodash.js)
|
||||||
|
|
|
||||||
|
|
@ -196,9 +196,6 @@ class Constants
|
||||||
# Other
|
# Other
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
|
|
||||||
# Application version
|
|
||||||
APP_VERSION = '1.12.1'.freeze
|
|
||||||
|
|
||||||
TEXT_EXTRACT_FILE_TYPES = [
|
TEXT_EXTRACT_FILE_TYPES = [
|
||||||
'application/pdf',
|
'application/pdf',
|
||||||
'application/rtf',
|
'application/rtf',
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ Devise.setup do |config|
|
||||||
# The period the generated invitation token is valid, after
|
# The period the generated invitation token is valid, after
|
||||||
# this period, the invited resource won't be able to accept the invitation.
|
# this period, the invited resource won't be able to accept the invitation.
|
||||||
# When invite_for is 0 (the default), the invitation won't expire.
|
# When invite_for is 0 (the default), the invitation won't expire.
|
||||||
config.invite_for = 3.days
|
config.invite_for = 7.days
|
||||||
|
|
||||||
# Number of invitations users can send.
|
# Number of invitations users can send.
|
||||||
# - If invitation_limit is nil, there is no limit for invitations, users can
|
# - If invitation_limit is nil, there is no limit for invitations, users can
|
||||||
|
|
@ -163,7 +163,7 @@ Devise.setup do |config|
|
||||||
# their account can't be confirmed with the token any more.
|
# their account can't be confirmed with the token any more.
|
||||||
# Default is nil, meaning there is no restriction on how long a user can take
|
# Default is nil, meaning there is no restriction on how long a user can take
|
||||||
# before confirming their account.
|
# before confirming their account.
|
||||||
config.confirm_within = 3.days
|
config.confirm_within = 7.days
|
||||||
|
|
||||||
# If true, requires any email changes to be confirmed (exactly the same way as
|
# If true, requires any email changes to be confirmed (exactly the same way as
|
||||||
# initial account confirmation) to be applied. Requires additional unconfirmed_email
|
# initial account confirmation) to be applied. Requires additional unconfirmed_email
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ module Paperclip
|
||||||
# Determine file content type from its name
|
# Determine file content type from its name
|
||||||
def content_types_from_name
|
def content_types_from_name
|
||||||
@content_types_from_name ||=
|
@content_types_from_name ||=
|
||||||
Paperclip.run('mimetype', '-b :file_name', file_name: @name).chomp
|
Paperclip.run('mimetype', '-b -- :file_name', file_name: @name).chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determine file media type from its name
|
# Determine file media type from its name
|
||||||
|
|
@ -92,7 +92,7 @@ module Paperclip
|
||||||
# Determine file content type from mimetype command
|
# Determine file content type from mimetype command
|
||||||
def type_from_mimetype_command
|
def type_from_mimetype_command
|
||||||
@type_from_mimetype_command ||=
|
@type_from_mimetype_command ||=
|
||||||
Paperclip.run('mimetype', '-b :file', file: @file.path).chomp
|
Paperclip.run('mimetype', '-b -- :file', file: @file.path).chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determine file media type from mimetype command
|
# Determine file media type from mimetype command
|
||||||
|
|
@ -105,7 +105,7 @@ module Paperclip
|
||||||
def type_from_file_command
|
def type_from_file_command
|
||||||
unless defined? @type_from_file_command
|
unless defined? @type_from_file_command
|
||||||
@type_from_file_command =
|
@type_from_file_command =
|
||||||
Paperclip.run('file', '-b --mime :file', file: @file.path)
|
Paperclip.run('file', '-b --mime -- :file', file: @file.path)
|
||||||
.split(/[:;]\s+/).first
|
.split(/[:;]\s+/).first
|
||||||
|
|
||||||
if allowed_spoof_exception?(@type_from_file_command,
|
if allowed_spoof_exception?(@type_from_file_command,
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ en:
|
||||||
support: "Customer support"
|
support: "Customer support"
|
||||||
premium: "Premium"
|
premium: "Premium"
|
||||||
contact: "Contact us"
|
contact: "Contact us"
|
||||||
|
about: "About sciNote"
|
||||||
activities:
|
activities:
|
||||||
none: "No activities!"
|
none: "No activities!"
|
||||||
label:
|
label:
|
||||||
|
|
@ -87,6 +88,11 @@ en:
|
||||||
info: "Info"
|
info: "Info"
|
||||||
account: "Account"
|
account: "Account"
|
||||||
|
|
||||||
|
about:
|
||||||
|
modal_title: "About sciNote"
|
||||||
|
core_version: "sciNote core version"
|
||||||
|
addon_versions: "Addon versions"
|
||||||
|
|
||||||
sidebar:
|
sidebar:
|
||||||
title: "Navigation"
|
title: "Navigation"
|
||||||
no_module_group: "No workflow"
|
no_module_group: "No workflow"
|
||||||
|
|
@ -905,8 +911,9 @@ en:
|
||||||
add_new_record: "Add new item"
|
add_new_record: "Add new item"
|
||||||
import_records:
|
import_records:
|
||||||
import: 'Import'
|
import: 'Import'
|
||||||
|
no_header_name: 'No column name'
|
||||||
success_flash: "%{number_of_rows} new item(s) successfully imported."
|
success_flash: "%{number_of_rows} new item(s) successfully imported."
|
||||||
error_flash: "Something went wrong: %{message}"
|
partial_success_flash: "%{nr} of %{total_nr} successfully imported. Other rows contained errors."
|
||||||
error_message:
|
error_message:
|
||||||
temp_file_not_found: "This file could not be found. Your session might expire."
|
temp_file_not_found: "This file could not be found. Your session might expire."
|
||||||
session_expired: "Your session expired. Please try again."
|
session_expired: "Your session expired. Please try again."
|
||||||
|
|
@ -944,7 +951,7 @@ en:
|
||||||
title: 'Import items'
|
title: 'Import items'
|
||||||
modal_import:
|
modal_import:
|
||||||
title: 'Import items'
|
title: 'Import items'
|
||||||
notice: 'You may upload .csv file (comma separated) or tab separated file (.txt or .tdv) or Excel file (.xls, .xlsx). First row should include header names, followed by rows with sample data.'
|
notice: 'You may upload .csv file (comma separated) or tab separated file (.txt or .tsv) or Excel file (.xlsx). First row should include header names, followed by rows with sample data.'
|
||||||
upload: 'Upload file'
|
upload: 'Upload file'
|
||||||
js:
|
js:
|
||||||
permission_error: "You don't have permission to edit this item."
|
permission_error: "You don't have permission to edit this item."
|
||||||
|
|
@ -1002,7 +1009,8 @@ en:
|
||||||
sample_type: "Sample type:"
|
sample_type: "Sample type:"
|
||||||
modal_import:
|
modal_import:
|
||||||
title: "Import samples"
|
title: "Import samples"
|
||||||
notice: "You may upload .csv file (comma separated) or tab separated file (.txt or .tdv) or Excel file (.xls, .xlsx). First row should include header names, followed by rows with sample data."
|
notice: "You may upload .csv file (comma separated) or tab separated file (.txt or .tsv) or Excel file (.xlsx). First row should include header names, followed by rows with sample data."
|
||||||
|
no_header_name: 'No column name'
|
||||||
upload: "Upload file"
|
upload: "Upload file"
|
||||||
modal_delete:
|
modal_delete:
|
||||||
title: "Delete samples"
|
title: "Delete samples"
|
||||||
|
|
|
||||||
|
|
@ -114,12 +114,16 @@ class AddonGenerator < Rails::Generators::NamedBase
|
||||||
gsub_file(file_path, '${ADDON_NAME}', @addon_name)
|
gsub_file(file_path, '${ADDON_NAME}', @addon_name)
|
||||||
|
|
||||||
# lib/.../version.rb
|
# lib/.../version.rb
|
||||||
|
dots = @modules.map { '/..' }.join
|
||||||
create_file(
|
create_file(
|
||||||
"addons/#{@addon_name}/lib/" \
|
"addons/#{@addon_name}/lib/" \
|
||||||
"#{@folders_path}/version.rb"
|
"#{@folders_path}/version.rb"
|
||||||
) do
|
) do
|
||||||
embed_into_modules do
|
embed_into_modules do
|
||||||
"VERSION = '0.0.1'.freeze\n"
|
"VERSION =\n" \
|
||||||
|
" File.read(\n" \
|
||||||
|
" \"\#{File.dirname(__FILE__)}#{dots}/../VERSION\"\n" \
|
||||||
|
" ).strip.freeze\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -182,6 +186,7 @@ class AddonGenerator < Rails::Generators::NamedBase
|
||||||
gsub_file(file_path, '${FULL_UNDERSCORE_NAME}', @full_underscore_name)
|
gsub_file(file_path, '${FULL_UNDERSCORE_NAME}', @full_underscore_name)
|
||||||
gsub_file(file_path, '${NAME}', name)
|
gsub_file(file_path, '${NAME}', name)
|
||||||
gsub_file(file_path, '${FOLDERS_PATH}', @folders_path)
|
gsub_file(file_path, '${FOLDERS_PATH}', @folders_path)
|
||||||
|
create_file("addons/#{@addon_name}/VERSION") { '0.0.1' }
|
||||||
|
|
||||||
# Rakefile
|
# Rakefile
|
||||||
file_path = "addons/#{@addon_name}/Rakefile"
|
file_path = "addons/#{@addon_name}/Rakefile"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue