diff --git a/Gemfile b/Gemfile index d8f544316..e28a8437a 100644 --- a/Gemfile +++ b/Gemfile @@ -62,6 +62,7 @@ gem 'logging', '~> 2.0.0' gem 'nested_form_fields' gem 'nokogiri', '~> 1.16.5' # HTML/XML parser gem 'noticed' +gem 'oj' gem 'rails_autolink', '~> 1.1', '>= 1.1.6' gem 'rgl' # Graph framework for project diagram calculations gem 'roo', '~> 2.10.0' # Spreadsheet parser diff --git a/Gemfile.lock b/Gemfile.lock index 83e1acc9f..82d0e20e7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,9 +97,9 @@ GEM erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - active_model_serializers (0.10.13) - actionpack (>= 4.1, < 7.1) - activemodel (>= 4.1, < 7.1) + active_model_serializers (0.10.14) + actionpack (>= 4.1) + activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) activejob (7.0.8.4) @@ -195,6 +195,7 @@ GEM erubi (>= 1.0.0) rack (>= 0.9.0) rouge (>= 1.0.0) + bigdecimal (3.1.8) bindata (2.5.0) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) @@ -202,7 +203,7 @@ GEM msgpack (~> 1.2) brakeman (6.1.2) racc - builder (3.2.4) + builder (3.3.0) bullet (7.0.7) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) @@ -316,7 +317,7 @@ GEM railties (>= 5) down (5.4.1) addressable (~> 2.8) - erubi (1.12.0) + erubi (1.13.0) et-orbi (1.2.11) tzinfo execjs (2.8.1) @@ -364,7 +365,7 @@ GEM httparty (0.21.0) mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) i18n-js (3.9.2) i18n (>= 0.6.6) @@ -372,7 +373,7 @@ GEM mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) iniparse (1.5.0) - jbuilder (2.11.5) + jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) jmespath (1.6.2) @@ -435,8 +436,7 @@ GEM mime-types-data (3.2023.0218.1) mini_magick (4.12.0) mini_mime (1.1.5) - mini_portile2 (2.8.7) - minitest (5.23.1) + minitest (5.25.1) msgpack (1.7.1) multi_json (1.15.0) multi_test (1.1.0) @@ -475,6 +475,9 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) + oj (3.16.6) + bigdecimal (>= 3.0) + ostruct (>= 0.2) omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) @@ -509,6 +512,7 @@ GEM validate_url webfinger (~> 2.0) orm_adapter (0.5.0) + ostruct (0.6.0) overcommit (0.60.0) childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) @@ -835,6 +839,7 @@ DEPENDENCIES newrelic_rpm nokogiri (~> 1.16.5) noticed + oj omniauth (~> 2.1) omniauth-azure-activedirectory-v2 omniauth-linkedin-oauth2 diff --git a/app/assets/javascripts/my_modules/repositories.js b/app/assets/javascripts/my_modules/repositories.js index 233b0e7e3..b34d7630f 100644 --- a/app/assets/javascripts/my_modules/repositories.js +++ b/app/assets/javascripts/my_modules/repositories.js @@ -433,10 +433,10 @@ var MyModuleRepositories = (function() { } function initSimpleTable() { - $('#assigned-items-container').on('shown.bs.collapse', '.assigned-repository-container.readable-repository', function() { + $('#assigned-items-container').on('shown.bs.collapse', '.assigned-repository-container', function() { var repositoryContainer = $(this); - var repositoryTable = repositoryContainer.find('.repository-table'); - var initializedTable = repositoryContainer.find('.dataTables_wrapper .repository-table'); + var repositoryTable = repositoryContainer.find('.table'); + var initializedTable = repositoryContainer.find('.dataTables_wrapper table'); // do not try to re-initialized already initialized table if (initializedTable.length) { diff --git a/app/assets/javascripts/repositories/repository_datatable.js b/app/assets/javascripts/repositories/repository_datatable.js index 9850f40af..933bed39a 100644 --- a/app/assets/javascripts/repositories/repository_datatable.js +++ b/app/assets/javascripts/repositories/repository_datatable.js @@ -317,9 +317,7 @@ var RepositoryDatatable = (function(global) { checkAvailableColumns(); - RepositoryDatatableRowEditor.switchRowToEditMode(row); - - changeToEditMode(); + RepositoryDatatableRowEditor.switchRowToEditMode(row, changeToEditMode); }); } @@ -692,6 +690,7 @@ var RepositoryDatatable = (function(global) { }, rowCallback: function(row, data) { $(row).attr('data-editable', data.recordEditable); + $(row).attr('data-info-url', data.recordInfoUrl); $(row).attr('data-manage-stock-url', data.manageStockUrl); // Get row ID let rowId = data.DT_RowId; @@ -1003,10 +1002,8 @@ var RepositoryDatatable = (function(global) { $(TABLE_ID).find('.repository-row-edit-icon').remove(); rowsSelected.forEach(function(rowNumber) { - RepositoryDatatableRowEditor.switchRowToEditMode(TABLE.row('#' + rowNumber)); + RepositoryDatatableRowEditor.switchRowToEditMode(TABLE.row('#' + rowNumber), changeToEditMode); }); - - changeToEditMode(); }) .on('click', '#assignRepositoryRecords', function(e) { e.preventDefault(); diff --git a/app/assets/javascripts/repositories/row_editor.js b/app/assets/javascripts/repositories/row_editor.js index 48a9517c8..490b6f63d 100644 --- a/app/assets/javascripts/repositories/row_editor.js +++ b/app/assets/javascripts/repositories/row_editor.js @@ -173,11 +173,17 @@ var RepositoryDatatableRowEditor = (function() { TABLE.columns.adjust(); } - function switchRowToEditMode(row) { + function enableEditMode(row, isEditable) { + if (!isEditable) { + HelperModule.flashAlertMsg(I18n.t('repositories.table.row_locked'), 'danger'); + return false; + } + let $row = $(row.node()); let itemId = row.id(); let formId = `repositoryRowForm${itemId}`; let requestUrl = $(TABLE.table().node()).data('current-uri'); + let rowForm = $(`
{ + if (enableEditMode(row, data.editable)) editEnabledCallback(); + } + }); } return Object.freeze({ diff --git a/app/controllers/my_module_repositories_controller.rb b/app/controllers/my_module_repositories_controller.rb index 396225f1b..d89dcb42b 100644 --- a/app/controllers/my_module_repositories_controller.rb +++ b/app/controllers/my_module_repositories_controller.rb @@ -15,7 +15,14 @@ class MyModuleRepositoriesController < ApplicationController @draw = params[:draw].to_i per_page = params[:length].to_i < 1 ? Constants::REPOSITORY_DEFAULT_PAGE_SIZE : params[:length].to_i page = (params[:start].to_i / per_page) + 1 - datatable_service = RepositoryDatatableService.new(@repository, params, current_user, @my_module) + if params[:simple_view] + rows_view = 'repository_rows/simple_view_index' + preload_cells = false + else + rows_view = 'repository_rows/index' + preload_cells = true + end + datatable_service = RepositoryDatatableService.new(@repository, params, current_user, @my_module, preload_cells: preload_cells) @datatable_params = { view_mode: params[:view_mode], @@ -26,21 +33,9 @@ class MyModuleRepositoriesController < ApplicationController @all_rows_count = datatable_service.all_count @columns_mappings = datatable_service.mappings - - if params[:simple_view] - repository_rows = datatable_service.repository_rows - rows_view = 'repository_rows/simple_view_index' - else - repository_rows = datatable_service.repository_rows - .preload(:repository_columns, - :created_by, - :archived_by, - :last_modified_by, - repository_cells: { value: @repository.cell_preload_includes }) - rows_view = 'repository_rows/index' - end + repository_rows = datatable_service.repository_rows @repository_rows = repository_rows.page(page).per(per_page) - + @filtered_rows_count = @repository_rows.load.take&.filtered_count || 0 render rows_view end diff --git a/app/controllers/my_module_repository_snapshots_controller.rb b/app/controllers/my_module_repository_snapshots_controller.rb index 2d0c6a128..6d1cff5d3 100644 --- a/app/controllers/my_module_repository_snapshots_controller.rb +++ b/app/controllers/my_module_repository_snapshots_controller.rb @@ -16,20 +16,16 @@ class MyModuleRepositorySnapshotsController < ApplicationController @all_rows_count = datatable_service.all_count @columns_mappings = datatable_service.mappings + repository_rows = datatable_service.repository_rows + if params[:simple_view] - repository_rows = datatable_service.repository_rows @repository = @repository_snapshot rows_view = 'repository_rows/simple_view_index' else - repository_rows = - datatable_service.repository_rows - .preload(:repository_columns, - :created_by, - repository_cells: { value: @repository_snapshot.cell_preload_includes }) rows_view = 'repository_rows/snapshot_index' end @repository_rows = repository_rows.page(page).per(per_page) - + @filtered_rows_count = @repository_rows.load.take&.filtered_count || 0 render rows_view end diff --git a/app/controllers/my_module_shareable_links_controller.rb b/app/controllers/my_module_shareable_links_controller.rb index 225825ab0..d49a6be5d 100644 --- a/app/controllers/my_module_shareable_links_controller.rb +++ b/app/controllers/my_module_shareable_links_controller.rb @@ -62,7 +62,7 @@ class MyModuleShareableLinksController < ApplicationController @draw = params[:draw].to_i per_page = params[:length].to_i < 1 ? Constants::REPOSITORY_DEFAULT_PAGE_SIZE : params[:length].to_i page = (params[:start].to_i / per_page) + 1 - datatable_service = RepositoryDatatableService.new(@repository, params, nil, @my_module) + datatable_service = RepositoryDatatableService.new(@repository, params, nil, @my_module, preload_cells: false) @datatable_params = { view_mode: params[:view_mode], @@ -76,6 +76,7 @@ class MyModuleShareableLinksController < ApplicationController @columns_mappings = datatable_service.mappings @repository_rows = datatable_service.repository_rows.page(page).per(per_page) + @filtered_rows_count = @repository_rows.load.take&.filtered_count || 0 render 'repository_rows/simple_view_index' end @@ -84,13 +85,14 @@ class MyModuleShareableLinksController < ApplicationController @draw = params[:draw].to_i per_page = params[:length].to_i < 1 ? Constants::REPOSITORY_DEFAULT_PAGE_SIZE : params[:length].to_i page = (params[:start].to_i / per_page) + 1 - datatable_service = RepositorySnapshotDatatableService.new(@repository_snapshot, params, nil, @my_module) + datatable_service = RepositorySnapshotDatatableService.new(@repository_snapshot, params, nil, @my_module, preload_cells: false) @all_rows_count = datatable_service.all_count @columns_mappings = datatable_service.mappings @repository = @repository_snapshot @repository_rows = datatable_service.repository_rows.page(page).per(per_page) + @filtered_rows_count = @repository_rows.load.take&.filtered_count || 0 render 'repository_rows/simple_view_index' end diff --git a/app/controllers/my_modules_controller.rb b/app/controllers/my_modules_controller.rb index 0d014874c..a9e941cd2 100644 --- a/app/controllers/my_modules_controller.rb +++ b/app/controllers/my_modules_controller.rb @@ -304,7 +304,7 @@ class MyModulesController < ApplicationController def protocols @protocol = @my_module.protocol - @assigned_repositories = @my_module.live_and_snapshot_repositories_list + @assigned_repositories = @my_module.readable_live_and_snapshot_repositories_list(current_user) end def protocol diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 65a831092..bddd1c863 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -44,11 +44,12 @@ class RepositoriesController < ApplicationController end def list - results = @repositories + results = @repositories.select(:id, :name, 'LOWER(repositories.name)') results = results.name_like(params[:query]) if params[:query].present? results = results.joins(:repository_rows).distinct if params[:non_empty].present? + results = results.active if params[:active].present? - render json: { data: results.map { |r| [r.id, r.name] } } + render json: { data: results.order('LOWER(repositories.name) asc').map { |r| [r.id, r.name] } } end def rows_list @@ -59,7 +60,15 @@ class RepositoriesController < ApplicationController params[:query] ) end - render json: { data: results.map { |r| [r.id, r.name] } } + results = results.active if params[:active].present? + + results = results.order('LOWER(repository_rows.name) asc').page(params[:page]) + + render json: { + paginated: true, + next_page: results.next_page, + data: results.map { |r| [r.id, r.name] } + } end def sidebar diff --git a/app/controllers/repository_rows_controller.rb b/app/controllers/repository_rows_controller.rb index 6a82de2a9..2e31001dc 100644 --- a/app/controllers/repository_rows_controller.rb +++ b/app/controllers/repository_rows_controller.rb @@ -28,16 +28,10 @@ class RepositoryRowsController < ApplicationController @all_rows_count = datatable_service.all_count @columns_mappings = datatable_service.mappings - @repository_rows = datatable_service.repository_rows - .preload(:repository_columns, - :created_by, - :archived_by, - :last_modified_by, - repository_cells: { value: @repository.cell_preload_includes }) - .page(page) - .per(per_page) - - @repository_rows = @repository_rows.where(archived: params[:archived]) unless @repository.archived? + repository_rows = datatable_service.repository_rows + repository_rows = repository_rows.where(archived: params[:archived]) unless @repository.archived? + @repository_rows = repository_rows.page(page).per(per_page) + @filtered_rows_count = @repository_rows.load.take&.filtered_count || 0 rescue RepositoryFilters::ColumnNotFoundException render json: { custom_error: I18n.t('repositories.show.repository_filter.errors.column_not_found') } rescue RepositoryFilters::ValueNotFoundException diff --git a/app/controllers/storage_location_repository_rows_controller.rb b/app/controllers/storage_location_repository_rows_controller.rb index 8aa723387..4ffa5365b 100644 --- a/app/controllers/storage_location_repository_rows_controller.rb +++ b/app/controllers/storage_location_repository_rows_controller.rb @@ -26,12 +26,14 @@ class StorageLocationRepositoryRowsController < ApplicationController created_by: current_user ) - if @storage_location_repository_row.save - log_activity(:storage_location_repository_row_created) - render json: @storage_location_repository_row, - serializer: Lists::StorageLocationRepositoryRowSerializer - else - render json: { errors: @storage_location_repository_row.errors.full_messages }, status: :unprocessable_entity + @storage_location_repository_row.with_lock do + if @storage_location_repository_row.save + log_activity(:storage_location_repository_row_created) + render json: @storage_location_repository_row, + serializer: Lists::StorageLocationRepositoryRowSerializer + else + render json: { errors: @storage_location_repository_row.errors.full_messages }, status: :unprocessable_entity + end end end end @@ -131,7 +133,7 @@ class StorageLocationRepositoryRowsController < ApplicationController .call(activity_type: type_of, owner: current_user, team: @storage_location.team, - subject: @storage_location_repository_row.repository_row, + subject: @storage_location_repository_row.storage_location, message_items: { storage_location: @storage_location_repository_row.storage_location_id, repository_row: @storage_location_repository_row.repository_row_id, diff --git a/app/controllers/storage_locations_controller.rb b/app/controllers/storage_locations_controller.rb index 965d766a0..13da18b9c 100644 --- a/app/controllers/storage_locations_controller.rb +++ b/app/controllers/storage_locations_controller.rb @@ -9,9 +9,9 @@ class StorageLocationsController < ApplicationController before_action :switch_team_with_param, only: %i(index show) before_action :check_storage_locations_enabled, except: :unassign_rows before_action :load_storage_location, only: %i(update destroy duplicate move show available_positions unassign_rows export_container import_container) - before_action :check_read_permissions, except: %i(index create tree actions_toolbar) + before_action :check_read_permissions, except: %i(index create tree actions_toolbar import_container unassign_rows) before_action :check_create_permissions, only: :create - before_action :check_manage_permissions, only: %i(update destroy duplicate move unassign_rows import_container) + before_action :check_manage_permissions, only: %i(update destroy duplicate move) before_action :set_breadcrumbs_items, only: %i(index show) def index @@ -86,7 +86,7 @@ class StorageLocationsController < ApplicationController def duplicate ActiveRecord::Base.transaction do - new_storage_location = @storage_location.duplicate! + new_storage_location = @storage_location.duplicate!(current_user) if new_storage_location @storage_location = new_storage_location log_activity('storage_location_created') @@ -123,8 +123,17 @@ class StorageLocationsController < ApplicationController end def tree - records = StorageLocation.viewable_by_user(current_user, current_team).where(parent: nil, container: [false, params[:container] == 'true']) - render json: storage_locations_recursive_builder(records) + records = StorageLocation.viewable_by_user(current_user, current_team) + .where( + parent: nil, + container: [false, params[:container] == 'true'] + ) + records = records.where(team_id: params[:team_id]) if params[:team_id] + + render json: { + locations: storage_locations_recursive_builder(records), + movable_to_root: params[:team_id] && current_team.id == params[:team_id].to_i + } end def available_positions @@ -253,7 +262,7 @@ class StorageLocationsController < ApplicationController end def storage_locations_recursive_builder(storage_locations) - storage_locations.map do |storage_location| + storage_locations.order('LOWER(storage_locations.name) ASC').map do |storage_location| { storage_location: storage_location, can_manage: (can_manage_storage_location?(storage_location) unless storage_location.parent_id), diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index 8e95ed31b..74d7fc180 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -163,9 +163,8 @@ module Users error_message ||= I18n.t('devise.okta.errors.generic') redirect_to after_omniauth_failure_path_for(resource_name) ensure - if user&.errors.present? || missing_attribute.present? - missing_attribute ||= user.errors.first.attribute.capitalize - set_flash_message(:alert, :missing_attribute, attribute: missing_attribute) + if user&.errors.present? + set_flash_message(:alert, :missing_attribute, attribute: user.errors.first.attribute.capitalize) elsif error_message set_flash_message(:alert, :failure, kind: I18n.t('devise.okta.provider_name'), reason: error_message) else diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 513a90ee7..5802404e7 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -141,10 +141,9 @@ module ApplicationHelper # Check if text have smart annotations of users # and outputs a popover with user information def smart_annotation_filter_users(text, team, base64_encoded_imgs: false) - sa_user = /\[\@(.*?)~([0-9a-zA-Z]+)\]/ - text.gsub(sa_user) do |el| - match = el.match(sa_user) - user = User.find_by_id(match[2].base62_decode) + text.gsub(SmartAnnotations::TagToHtml::USER_REGEX) do |el| + match = el.match(SmartAnnotations::TagToHtml::USER_REGEX) + user = User.find_by(id: match[2].base62_decode) next unless user popover_for_user_name(user, team, false, false, base64_encoded_imgs) diff --git a/app/helpers/global_activities_helper.rb b/app/helpers/global_activities_helper.rb index 17aecb5a2..af945712a 100644 --- a/app/helpers/global_activities_helper.rb +++ b/app/helpers/global_activities_helper.rb @@ -3,6 +3,7 @@ module GlobalActivitiesHelper include ActionView::Helpers::AssetTagHelper include ActionView::Helpers::UrlHelper + include Canaid::Helpers::PermissionsHelper include InputSanitizeHelper def generate_activity_content(activity, no_links: false, no_custom_links: false) @@ -60,6 +61,9 @@ module GlobalActivitiesHelper when Repository path = repository_path(obj, team: obj.team.id) when RepositoryRow + # Handle private repository rows + return I18n.t('storage_locations.show.hidden') unless can_read_repository?(obj.repository) + return current_value unless obj.repository path = repository_path(obj.repository, team: obj.repository.team.id) @@ -127,6 +131,8 @@ module GlobalActivitiesHelper message_item['type'].constantize.new end + return I18n.t('storage_locations.show.hidden') if obj.is_a?(RepositoryRow) && !can_read_repository?(obj.repository) + return I18n.t('projects.index.breadcrumbs_root') if obj.is_a?(ProjectFolder) && obj.new_record? return I18n.t('storage_locations.index.breadcrumbs_root') if obj.is_a?(StorageLocation) && obj.new_record? diff --git a/app/helpers/input_sanitize_helper.rb b/app/helpers/input_sanitize_helper.rb index e30a23666..73c9eaca2 100644 --- a/app/helpers/input_sanitize_helper.rb +++ b/app/helpers/input_sanitize_helper.rb @@ -46,9 +46,8 @@ module InputSanitizeHelper sanitizer_config = Constants::INPUT_SANITIZE_CONFIG.deep_dup text = sanitize_input(text, tags, sanitizer_config: sanitizer_config) - if text =~ SmartAnnotations::TagToHtml::USER_REGEX || text =~ SmartAnnotations::TagToHtml::REGEX - text = smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository) - end + text = smart_annotation_parser(text, team, base64_encoded_imgs, preview_repository) if text.match?(SmartAnnotations::TagToHtml::ALL_REGEX) + auto_link( text, html: { target: '_blank' }, diff --git a/app/helpers/repository_datatable_helper.rb b/app/helpers/repository_datatable_helper.rb index aa78df6aa..2f64004d0 100644 --- a/app/helpers/repository_datatable_helper.rb +++ b/app/helpers/repository_datatable_helper.rb @@ -5,44 +5,38 @@ module RepositoryDatatableHelper include Rails.application.routes.url_helpers def prepare_row_columns(repository_rows, repository, columns_mappings, team, options = {}) + # repository_rows collection is already preloaded in controllers, do not modify scopes or query params + # otherwise it will result in duplicated SQL queries has_stock_management = repository.has_stock_management? stock_management_column_exists = repository.repository_columns.stock_type.exists? repository_row_connections_enabled = Repository.repository_row_connections_enabled? reminders_enabled = Repository.reminders_enabled? - repository_rows = reminders_enabled ? with_reminders_status(repository_rows, repository) : repository_rows stock_managable = has_stock_management && !options[:disable_stock_management] && can_manage_repository_stock?(repository) && !repository.is_a?(SoftLockedRepository) stock_consumption_permitted = has_stock_management && options[:include_stock_consumption] && options[:my_module] && stock_consumption_permitted?(repository, options[:my_module]) + default_columns_method_name = "#{repository.class.name.underscore}_default_columns" repository_rows.map do |record| - row = public_send("#{repository.class.name.underscore}_default_columns", record) - row.merge!( - DT_RowId: record.id, - DT_RowAttr: { 'data-state': row_style(record), 'data-e2e': "e2e-TR-invInventory-bodyRow-#{record.id}" }, - recordInfoUrl: Rails.application.routes.url_helpers.repository_repository_row_path(repository, record), - rowRemindersUrl: - Rails.application.routes.url_helpers - .active_reminder_repository_cells_repository_repository_row_url( - repository, - record - ), - relationshipsUrl: - Rails.application.routes.url_helpers - .relationships_repository_repository_row_url(record.repository_id, record.id), - relationships_enabled: repository_row_connections_enabled, - code: record.code - ) - - if reminders_enabled - row['hasActiveReminders'] = record.has_active_stock_reminders || record.has_active_datetime_reminders - end + row = public_send(default_columns_method_name, record) + row['code'] = record.code + row['DT_RowId'] = record.id + row['DT_RowAttr'] = { 'data-state': row_style(record), 'data-e2e': "e2e-TR-invInventory-bodyRow-#{record.id}" } + row['recordInfoUrl'] = Rails.application.routes.url_helpers.repository_repository_row_path(repository.id, record.id) + row['rowRemindersUrl'] = Rails.application.routes.url_helpers + .active_reminder_repository_cells_repository_repository_row_url(repository.id, record.id) + row['relationshipsUrl'] = Rails.application.routes.url_helpers + .relationships_repository_repository_row_url(record.repository_id, record.id) + row['relationships_enabled'] = repository_row_connections_enabled + row['hasActiveReminders'] = record.has_active_reminders if reminders_enabled unless options[:view_mode] || repository.is_a?(SoftLockedRepository) row['recordUpdateUrl'] = Rails.application.routes.url_helpers.repository_repository_row_path(repository, record) - row['recordEditable'] = record.editable? + + # if the editable? property will be checked in a separate request, we can default it to true + row['recordEditable'] = options[:omit_editable] ? true : record.editable? end row['0'] = record[:row_assigned] if options[:my_module] @@ -51,8 +45,7 @@ module RepositoryDatatableHelper custom_cells = record.repository_cells.filter { |cell| cell.value_type != 'RepositoryStockValue' } custom_cells.each do |cell| - row[columns_mappings[cell.repository_column.id]] = - serialize_repository_cell_value(cell, team, repository, reminders_enabled: reminders_enabled) + row[columns_mappings[cell.repository_column_id]] = serialize_repository_cell_value(cell, team, repository, reminders_enabled: reminders_enabled) end if has_stock_management @@ -105,9 +98,10 @@ module RepositoryDatatableHelper end def prepare_simple_view_row_columns(repository_rows, repository, my_module, options = {}) + # repository_rows collection is already preloaded in controllers, do not modify scopes or query params + # otherwise it will result in duplicated SQL queries has_stock_management = repository.has_stock_management? reminders_enabled = !options[:disable_reminders] && Repository.reminders_enabled? - repository_rows = reminders_enabled ? with_reminders_status(repository_rows, repository) : repository_rows # Always disabled in a simple view stock_managable = false stock_consumption_permitted = has_stock_management && stock_consumption_permitted?(repository, my_module) @@ -126,9 +120,7 @@ module RepositoryDatatableHelper ) } - if reminders_enabled - row['hasActiveReminders'] = record.has_active_stock_reminders || record.has_active_datetime_reminders - end + row['hasActiveReminders'] = record.has_active_reminders if reminders_enabled if has_stock_management stock_present = record.repository_stock_cell.present? @@ -193,15 +185,14 @@ module RepositoryDatatableHelper '1': record.code, '2': escape_input(record.name), '3': I18n.l(record.created_at, format: :full), - '4': escape_input(record.created_by.full_name), + '4': escape_input(record.created_by_full_name), 'recordInfoUrl': Rails.application.routes.url_helpers .repository_repository_row_path(repository_snapshot, record) } # Add custom columns record.repository_cells.each do |cell| - row[columns_mappings[cell.repository_column.id]] = - serialize_repository_cell_value(cell, team, repository_snapshot) + row[columns_mappings[cell.repository_column_id]] = serialize_repository_cell_value(cell, team, repository_snapshot) end if has_stock_management @@ -239,11 +230,11 @@ module RepositoryDatatableHelper '3': escape_input(record.name), '4': "#{record.parent_connections_count || 0} / #{record.child_connections_count || 0}", '5': I18n.l(record.created_at, format: :full), - '6': escape_input(record.created_by.full_name), + '6': escape_input(record.created_by_full_name), '7': (record.updated_at ? I18n.l(record.updated_at, format: :full) : ''), - '8': escape_input(record.last_modified_by.full_name), + '8': escape_input(record.last_modified_by_full_name), '9': (record.archived_on ? I18n.l(record.archived_on, format: :full) : ''), - '10': escape_input(record.archived_by&.full_name) + '10': escape_input(record.archived_by_full_name) } end @@ -254,9 +245,9 @@ module RepositoryDatatableHelper '3': escape_input(record.name), '4': "#{record.parent_connections_count || 0} / #{record.child_connections_count || 0}", '5': I18n.l(record.created_at, format: :full), - '6': escape_input(record.created_by.full_name), + '6': escape_input(record.created_by_full_name), '7': (record.archived_on ? I18n.l(record.archived_on, format: :full) : ''), - '8': escape_input(record.archived_by&.full_name) + '8': escape_input(record.archived_by_full_name) } end @@ -266,9 +257,9 @@ module RepositoryDatatableHelper '2': record.code, '3': escape_input(record.name), '4': I18n.l(record.created_at, format: :full), - '5': escape_input(record.created_by.full_name), + '5': escape_input(record.created_by_full_name), '6': (record.archived_on ? I18n.l(record.archived_on, format: :full) : ''), - '7': escape_input(record.archived_by&.full_name), + '7': escape_input(record.archived_by_full_name), '8': escape_input(record.external_id) } end @@ -313,35 +304,6 @@ module RepositoryDatatableHelper '' end - def with_reminders_status(repository_rows, repository) - # don't load reminders for archived repositories or snapshots - if repository.archived? || repository.is_a?(RepositorySnapshot) - return repository_rows.select('FALSE AS has_active_stock_reminders') - .select('FALSE AS has_active_datetime_reminders') - end - - 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) return false unless repository.is_a?(Repository) && current_user diff --git a/app/helpers/storage_locations_helper.rb b/app/helpers/storage_locations_helper.rb index 1e0b6d651..8754ad523 100644 --- a/app/helpers/storage_locations_helper.rb +++ b/app/helpers/storage_locations_helper.rb @@ -1,5 +1,7 @@ module StorageLocationsHelper def storage_locations_placeholder + return if StorageLocation.storage_locations_enabled? + "
#{I18n.t('storage_locations.storage_locations_disabled')}
" diff --git a/app/javascript/vue/repository_item_sidebar/locations.vue b/app/javascript/vue/repository_item_sidebar/locations.vue index d496fd4ad..88cd3e30a 100644 --- a/app/javascript/vue/repository_item_sidebar/locations.vue +++ b/app/javascript/vue/repository_item_sidebar/locations.vue @@ -7,7 +7,10 @@ {{ i18n.t('repositories.locations.assign') }} -