mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-06 05:04:35 +08:00
Fix importing files with empty header cells and error messages improvements [SCI-1484]
This commit is contained in:
parent
036ee390ed
commit
ece27b2652
9 changed files with 65 additions and 54 deletions
2
Gemfile
2
Gemfile
|
@ -46,7 +46,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'
|
||||||
|
|
10
Gemfile.lock
10
Gemfile.lock
|
@ -190,9 +190,8 @@ GEM
|
||||||
jquery-rails
|
jquery-rails
|
||||||
rails (>= 3.2.0)
|
rails (>= 3.2.0)
|
||||||
newrelic_rpm (4.0.0.332)
|
newrelic_rpm (4.0.0.332)
|
||||||
nokogiri (1.6.8)
|
nokogiri (1.6.8.1)
|
||||||
mini_portile2 (~> 2.1.0)
|
mini_portile2 (~> 2.1.0)
|
||||||
pkg-config (~> 1.1.7)
|
|
||||||
nokogumbo (1.4.10)
|
nokogumbo (1.4.10)
|
||||||
nokogiri
|
nokogiri
|
||||||
oj (2.17.4)
|
oj (2.17.4)
|
||||||
|
@ -206,7 +205,6 @@ GEM
|
||||||
parser (2.4.0.0)
|
parser (2.4.0.0)
|
||||||
ast (~> 2.2)
|
ast (~> 2.2)
|
||||||
pg (0.18.4)
|
pg (0.18.4)
|
||||||
pkg-config (1.1.7)
|
|
||||||
polyglot (0.3.5)
|
polyglot (0.3.5)
|
||||||
powerpack (0.1.1)
|
powerpack (0.1.1)
|
||||||
puma (2.15.3)
|
puma (2.15.3)
|
||||||
|
@ -257,7 +255,7 @@ GEM
|
||||||
algorithms (~> 0.6.1)
|
algorithms (~> 0.6.1)
|
||||||
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)
|
||||||
rubocop (0.48.1)
|
rubocop (0.48.1)
|
||||||
|
@ -268,7 +266,7 @@ GEM
|
||||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
ruby-graphviz (1.2.2)
|
ruby-graphviz (1.2.2)
|
||||||
ruby-progressbar (1.8.1)
|
ruby-progressbar (1.8.1)
|
||||||
rubyzip (1.1.7)
|
rubyzip (1.2.1)
|
||||||
sanitize (4.4.0)
|
sanitize (4.4.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.4.4)
|
nokogiri (>= 1.4.4)
|
||||||
|
@ -390,7 +388,7 @@ DEPENDENCIES
|
||||||
recaptcha
|
recaptcha
|
||||||
remotipart (~> 1.2)
|
remotipart (~> 1.2)
|
||||||
rgl
|
rgl
|
||||||
roo (~> 2.1.0)
|
roo (~> 2.7.1)
|
||||||
rubocop
|
rubocop
|
||||||
ruby-graphviz (~> 1.2)
|
ruby-graphviz (~> 1.2)
|
||||||
rubyzip
|
rubyzip
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -109,9 +109,10 @@ class Repository < ActiveRecord::Base
|
||||||
|
|
||||||
# Imports records
|
# Imports records
|
||||||
def import_records(sheet, mappings, user)
|
def import_records(sheet, mappings, user)
|
||||||
errors = []
|
errors = false
|
||||||
custom_fields = []
|
custom_fields = []
|
||||||
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|
|
||||||
|
@ -127,13 +128,17 @@ class Repository < ActiveRecord::Base
|
||||||
|
|
||||||
# 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|
|
(2..sheet.last_row).each do |i|
|
||||||
error = []
|
total_nr += 1
|
||||||
|
cell_error = false
|
||||||
record_row = RepositoryRow.new(name: sheet.row(i)[name_index],
|
record_row = RepositoryRow.new(name: sheet.row(i)[name_index],
|
||||||
repository: self,
|
repository: self,
|
||||||
created_by: user,
|
created_by: user,
|
||||||
last_modified_by: user)
|
last_modified_by: user)
|
||||||
|
|
||||||
next unless record_row.valid?
|
unless record_row.valid?
|
||||||
|
errors = true
|
||||||
|
next
|
||||||
|
end
|
||||||
sheet.row(i).each.with_index do |value, index|
|
sheet.row(i).each.with_index do |value, index|
|
||||||
if custom_fields[index] && value
|
if custom_fields[index] && value
|
||||||
rep_column = RepositoryTextValue.new(
|
rep_column = RepositoryTextValue.new(
|
||||||
|
@ -145,10 +150,11 @@ class Repository < ActiveRecord::Base
|
||||||
repository_column: custom_fields[index]
|
repository_column: custom_fields[index]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
error << rep_column.errors.messages unless rep_column.save
|
cell_error = true unless rep_column.save
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if error.any?
|
if cell_error
|
||||||
|
errors = true
|
||||||
record_row.destroy
|
record_row.destroy
|
||||||
else
|
else
|
||||||
nr_of_added += 1
|
nr_of_added += 1
|
||||||
|
@ -156,10 +162,12 @@ class Repository < ActiveRecord::Base
|
||||||
end
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -911,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."
|
||||||
|
@ -1009,6 +1010,7 @@ en:
|
||||||
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 .tdv) or Excel file (.xls, .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"
|
||||||
|
|
Loading…
Add table
Reference in a new issue