Improve loading speed of inventory table [SCI-7638]

This commit is contained in:
Oleksii Kriuchykhin 2023-01-16 10:46:35 +01:00
parent 9f6887ddcc
commit e51cf28ec6
20 changed files with 143 additions and 78 deletions

View file

@ -412,10 +412,10 @@ var RepositoryDatatable = (function(global) {
// Adjust columns width in table header
function adjustTableHeader() {
TABLE.columns.adjust();
$('.dropdown-menu').parent()
.on('shown.bs.dropdown hidden.bs.dropdown', function() {
TABLE.columns.adjust();
});
// $('.dropdown-menu').parent()
// .on('shown.bs.dropdown hidden.bs.dropdown', function() {
// TABLE.columns.adjust();
// });
}
function checkSnapshottingStatus() {
@ -664,9 +664,9 @@ var RepositoryDatatable = (function(global) {
initActiveRemindersFilter();
renderFiltersDropdown();
setTimeout(function() {
adjustTableHeader();
}, 500);
// setTimeout(function() {
// adjustTableHeader();
// }, 500);
}
});
@ -699,11 +699,11 @@ var RepositoryDatatable = (function(global) {
})
initRowSelection();
$(window).resize(() => {
setTimeout(() => {
adjustTableHeader();
}, 500);
});
// $(window).resize(() => {
// setTimeout(() => {
// adjustTableHeader();
// }, 500);
// });
return TABLE;
}
@ -822,7 +822,7 @@ var RepositoryDatatable = (function(global) {
});
changeToEditMode();
adjustTableHeader();
// adjustTableHeader();
})
.on('click', '#deleteRepositoryRecords', function() {
$('#deleteRepositoryRecord').modal('show');
@ -909,9 +909,9 @@ var RepositoryDatatable = (function(global) {
document.documentElement.style.setProperty('--repository-sidebar-margin', '363px');
});
$('#wrapper').on('sideBar::hidden sideBar::shown', function() {
adjustTableHeader();
});
// $('#wrapper').on('sideBar::hidden sideBar::shown', function() {
// adjustTableHeader();
// });
}
function renderFiltersDropdown() {

View file

@ -28,11 +28,14 @@ module InputSanitizeHelper
base64_encoded_imgs = options.fetch(:base64_encoded_imgs, false)
text = sanitize_input(text, tags)
text = simple_format(text, {}, format_opt) if simple_f
if text =~ SmartAnnotations::TagToHtml::USER_REGEX || text =~ SmartAnnotations::TagToHtml::REGEX
text = smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository)
end
auto_link(
custom_link_open_new_tab(smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository)),
text,
html: { target: '_blank' },
link: :urls,
sanitize: false,
html: { target: '_blank' }
sanitize: false
).html_safe
end
end

View file

@ -6,22 +6,22 @@ module RepositoryDatatableHelper
def prepare_row_columns(repository_rows, repository, columns_mappings, team, options = {})
has_stock_management = repository.has_stock_management?
reminders_enabled = Repository.reminders_enabled?
reminder_row_ids = reminders_enabled ? repository_reminder_row_ids(repository_rows, repository) : []
repository_rows = reminders_enabled ? with_reminders_status(repository_rows, repository) : repository_rows
repository_rows.map do |record|
default_cells = public_send("#{repository.class.name.underscore}_default_columns", record)
row = {
row = public_send("#{repository.class.name.underscore}_default_columns", record)
row.merge!(
DT_RowId: record.id,
DT_RowAttr: { 'data-state': row_style(record) },
recordInfoUrl: Rails.application.routes.url_helpers.repository_repository_row_path(repository, record),
hasActiveReminders: reminder_row_ids.include?(record.id),
hasActiveReminders: record.has_active_stock_reminders || record.has_active_datetime_reminders,
rowRemindersUrl:
Rails.application.routes.url_helpers
.active_reminder_repository_cells_repository_repository_row_url(
repository,
record
)
}.merge(default_cells)
)
if has_stock_management
row['manageStockUrl'] = if record.has_stock?
@ -100,7 +100,7 @@ module RepositoryDatatableHelper
def prepare_simple_view_row_columns(repository_rows, repository, my_module, options = {})
has_stock_management = repository.has_stock_management?
reminders_enabled = Repository.reminders_enabled?
reminder_row_ids = reminders_enabled ? repository_reminder_row_ids(repository_rows, repository) : []
repository_rows = reminders_enabled ? with_reminders_status(repository_rows, repository) : repository_rows
repository_rows.map do |record|
row = {
@ -108,7 +108,7 @@ module RepositoryDatatableHelper
DT_RowAttr: { 'data-state': row_style(record) },
'0': escape_input(record.name),
recordInfoUrl: Rails.application.routes.url_helpers.repository_repository_row_path(record.repository, record),
hasActiveReminders: reminder_row_ids.include?(record.id),
hasActiveReminders: record.has_active_stock_reminders || record.has_active_datetime_reminders,
rowRemindersUrl:
Rails.application.routes.url_helpers
.active_reminder_repository_cells_repository_repository_row_url(
@ -275,14 +275,33 @@ module RepositoryDatatableHelper
''
end
def repository_reminder_row_ids(repository_rows, repository)
def with_reminders_status(repository_rows, repository)
# don't load reminders for archived repositories
return [] if repository_rows.blank? || repository.archived?
return repository_rows if repository.archived?
# don't load reminders for snapshots
return [] if repository.is_a?(RepositorySnapshot)
return repository_rows if repository.is_a?(RepositorySnapshot)
repository_rows.active.with_active_reminders(current_user).to_a.pluck(:id).uniq
repository_cells = RepositoryCell.joins(
"INNER JOIN repository_columns ON repository_columns.id = repository_cells.repository_column_id " \
"AND repository_columns.repository_id = #{repository.id}"
)
repository_rows
.joins(
"LEFT OUTER JOIN (#{RepositoryCell.stock_reminder_repository_cells_scope(repository_cells, current_user)
.select(:id, :repository_row_id).to_sql}) " \
"AS repository_cells_with_active_stock_reminders " \
"ON repository_cells_with_active_stock_reminders.repository_row_id = repository_rows.id"
)
.joins(
"LEFT OUTER JOIN (#{RepositoryCell.date_time_reminder_repository_cells_scope(repository_cells, current_user)
.select(:id, :repository_row_id).to_sql}) " \
"AS repository_cells_with_active_datetime_reminders " \
"ON repository_cells_with_active_datetime_reminders.repository_row_id = repository_rows.id"
)
.select('COUNT(repository_cells_with_active_stock_reminders.id) > 0 AS has_active_stock_reminders')
.select('COUNT(repository_cells_with_active_datetime_reminders.id) > 0 AS has_active_datetime_reminders')
end
def stock_consumption_permitted?(repository, my_module)

View file

@ -27,5 +27,38 @@ module ReminderRepositoryCellJoinable
'(repository_date_time_values.id IS NOT NULL OR repository_stock_values.id IS NOT NULL)'
)
end
def self.stock_reminder_repository_cells_scope(relation, user)
relation.joins( # stock reminders
'LEFT OUTER JOIN "repository_stock_values" ON ' \
'"repository_cells"."value_type" = \'RepositoryStockValue\' AND ' \
'"repository_stock_values"."id" = "repository_cells"."value_id" AND ' \
'(repository_stock_values.amount <= repository_stock_values.low_stock_threshold OR ' \
'repository_stock_values.amount <= 0)'
).joins(
'LEFT OUTER JOIN "hidden_repository_cell_reminders" ON ' \
'"repository_cells"."id" = "hidden_repository_cell_reminders"."repository_cell_id" AND ' \
'"hidden_repository_cell_reminders"."user_id" = ' + user.id.to_s
).where(
'hidden_repository_cell_reminders.id IS NULL AND repository_stock_values.id IS NOT NULL'
)
end
def self.date_time_reminder_repository_cells_scope(relation, user)
relation.joins( # datetime reminders
'LEFT OUTER JOIN "repository_date_time_values" ON ' \
'"repository_date_time_values"."id" = "repository_cells"."value_id" AND ' \
'"repository_cells"."value_type" = \'RepositoryDateTimeValueBase\' ' \
'AND repository_columns.metadata ->> \'reminder_delta\' <> \'\' AND ' \
'(repository_date_time_values.data - NOW()) <= ' \
'(repository_columns.metadata ->> \'reminder_delta\')::int * interval \'1 sec\''
).joins(
'LEFT OUTER JOIN "hidden_repository_cell_reminders" ON ' \
'"repository_cells"."id" = "hidden_repository_cell_reminders"."repository_cell_id" AND ' \
'"hidden_repository_cell_reminders"."user_id" = ' + user.id.to_s
).where(
'hidden_repository_cell_reminders.id IS NULL AND repository_date_time_values.id IS NOT NULL'
)
end
end
end

View file

@ -5,7 +5,7 @@ module RepositoryDatatable
include Rails.application.routes.url_helpers
def value
asset = object.asset
asset = value_object.asset
{
id: asset.id,
url: rails_blob_path(asset.file, disposition: 'attachment'),

View file

@ -1,15 +1,24 @@
# frozen_string_literal: true
module RepositoryDatatable
class RepositoryBaseValueSerializer < ActiveModel::Serializer
attributes :value, :value_type
class RepositoryBaseValueSerializer
attr_accessor :value_object, :value_type, :scope
def initialize(value, scope:)
@value_object = value
@value_type = value.class.name
@scope = scope
end
def serializable_hash
{
value: value,
value_type: @value_type
}
end
def value
raise NotImplementedError
end
def value_type
object.class.name
end
end
end

View file

@ -4,7 +4,7 @@ module RepositoryDatatable
class RepositoryChecklistValueSerializer < RepositoryBaseValueSerializer
include InputSanitizeHelper
def value
object.data.each { |i| i[:label] = escape_input(i[:label]) }
value_object.data.each { |i| i[:label] = escape_input(i[:label]) }
end
end
end

View file

@ -5,12 +5,12 @@ module RepositoryDatatable
def value
{
start_time: {
formatted: I18n.l(object.start_time, format: :full_date),
datetime: object.start_time.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.start_time, format: :full_date),
datetime: value_object.start_time.strftime('%Y/%m/%d %H:%M')
},
end_time: {
formatted: I18n.l(object.end_time, format: :full_date),
datetime: object.end_time.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.end_time, format: :full_date),
datetime: value_object.end_time.strftime('%Y/%m/%d %H:%M')
}
}
end

View file

@ -5,16 +5,16 @@ module RepositoryDatatable
def value
{
start_time: {
formatted: I18n.l(object.start_time, format: :full_with_comma),
date_formatted: I18n.l(object.start_time, format: :full_date),
time_formatted: I18n.l(object.start_time, format: :time),
datetime: object.start_time.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.start_time, format: :full_with_comma),
date_formatted: I18n.l(value_object.start_time, format: :full_date),
time_formatted: I18n.l(value_object.start_time, format: :time),
datetime: value_object.start_time.strftime('%Y/%m/%d %H:%M')
},
end_time: {
formatted: I18n.l(object.end_time, format: :full_with_comma),
date_formatted: I18n.l(object.end_time, format: :full_date),
time_formatted: I18n.l(object.end_time, format: :time),
datetime: object.end_time.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.end_time, format: :full_with_comma),
date_formatted: I18n.l(value_object.end_time, format: :full_date),
time_formatted: I18n.l(value_object.end_time, format: :time),
datetime: value_object.end_time.strftime('%Y/%m/%d %H:%M')
}
}
end

View file

@ -4,16 +4,16 @@ module RepositoryDatatable
class RepositoryDateTimeValueSerializer < RepositoryBaseValueSerializer
def value
data = {
formatted: I18n.l(object.data, format: :full_with_comma),
date_formatted: I18n.l(object.data, format: :full_date),
time_formatted: I18n.l(object.data, format: :time),
datetime: object.data.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.data, format: :full_with_comma),
date_formatted: I18n.l(value_object.data, format: :full_date),
time_formatted: I18n.l(value_object.data, format: :time),
datetime: value_object.data.strftime('%Y/%m/%d %H:%M')
}
if scope.dig(:options, :reminders_enabled)
reminder_delta = scope[:column].metadata['reminder_delta']
if !scope[:repository].is_a?(RepositorySnapshot) && reminder_delta
data[:reminder] = reminder_delta.to_i + DateTime.now.to_i >= object.data.to_i
data[:reminder] = reminder_delta.to_i + DateTime.now.to_i >= value_object.data.to_i
end
end

View file

@ -4,14 +4,14 @@ module RepositoryDatatable
class RepositoryDateValueSerializer < RepositoryBaseValueSerializer
def value
data = {
formatted: I18n.l(object.data, format: :full_date),
datetime: object.data.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.data, format: :full_date),
datetime: value_object.data.strftime('%Y/%m/%d %H:%M')
}
if scope.dig(:options, :reminders_enabled)
reminder_delta = scope[:column].metadata['reminder_delta']
if !scope[:repository].is_a?(RepositorySnapshot) && reminder_delta
data[:reminder] = DateTime.now + reminder_delta.to_i.seconds >= object.data
data[:reminder] = DateTime.now + reminder_delta.to_i.seconds >= value_object.data
end
end

View file

@ -5,8 +5,8 @@ module RepositoryDatatable
include InputSanitizeHelper
def value
{
id: (object.repository_list_item&.id || ''),
text: (escape_input(object.data) || '')
id: (value_object.repository_list_item&.id || ''),
text: (escape_input(value_object.data) || '')
}
end
end

View file

@ -4,7 +4,7 @@ module RepositoryDatatable
class RepositoryNumberValueSerializer < RepositoryBaseValueSerializer
def value
decimals = scope[:column].metadata.fetch('decimals', Constants::REPOSITORY_NUMBER_TYPE_DEFAULT_DECIMALS).to_i
object.data.round(decimals).to_s('F').remove(/.0+$/)
value_object.data.round(decimals).to_s('F').remove(/.0+$/)
end
end
end

View file

@ -5,9 +5,9 @@ module RepositoryDatatable
include InputSanitizeHelper
def value
{
id: object.repository_status_item.id,
icon: object.repository_status_item.icon,
status: escape_input(object.repository_status_item.status)
id: value_object.repository_status_item.id,
icon: value_object.repository_status_item.icon,
status: escape_input(value_object.repository_status_item.status)
}
end
end

View file

@ -4,8 +4,8 @@ module RepositoryDatatable
class RepositoryStockConsumptionValueSerializer < RepositoryBaseValueSerializer
def value
{
consumed_stock_formatted: object.formatted,
consumed_stock: object.data
consumed_stock_formatted: value_object.formatted,
consumed_stock: value_object.data
}
end
end

View file

@ -6,9 +6,9 @@ module RepositoryDatatable
def value
{
stock_formatted: object.formatted,
stock_amount: object.data,
low_stock_threshold: object.low_stock_threshold
stock_formatted: value_object.formatted,
stock_amount: value_object.data,
low_stock_threshold: value_object.low_stock_threshold
}
end
end

View file

@ -9,8 +9,8 @@ module RepositoryDatatable
def value
@user = scope[:user]
{
view: custom_auto_link(object.data, simple_format: true, team: scope[:team]),
edit: object.data
view: custom_auto_link(value_object.data, simple_format: true, team: scope[:team]),
edit: value_object.data
}
end
end

View file

@ -5,12 +5,12 @@ module RepositoryDatatable
def value
{
start_time: {
formatted: I18n.l(object.start_time, format: :time),
datetime: object.start_time.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.start_time, format: :time),
datetime: value_object.start_time.strftime('%Y/%m/%d %H:%M')
},
end_time: {
formatted: I18n.l(object.end_time, format: :time),
datetime: object.end_time.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.end_time, format: :time),
datetime: value_object.end_time.strftime('%Y/%m/%d %H:%M')
}
}
end

View file

@ -4,8 +4,8 @@ module RepositoryDatatable
class RepositoryTimeValueSerializer < RepositoryBaseValueSerializer
def value
{
formatted: I18n.l(object.data, format: :time),
datetime: object.data.strftime('%Y/%m/%d %H:%M')
formatted: I18n.l(value_object.data, format: :time),
datetime: value_object.data.strftime('%Y/%m/%d %H:%M')
}
end
end

View file

@ -2,6 +2,8 @@
module SmartAnnotations
class TagToHtml
REGEX = /\[\#(.*?)~(prj|exp|tsk|rep_item)~([0-9a-zA-Z]+)\]/.freeze
USER_REGEX = /\[@(.*?)~([0-9a-zA-Z]+)\]/.freeze
attr_reader :html
def initialize(user, team, text, preview_repository = false)
@ -10,7 +12,6 @@ module SmartAnnotations
private
REGEX = /\[\#(.*?)~(prj|exp|tsk|rep_item)~([0-9a-zA-Z]+)\]/
OBJECT_MAPPINGS = { prj: Project,
exp: Experiment,
tsk: MyModule,