Implement quick search backend [SCI-10246]

This commit is contained in:
Andrej 2024-02-27 12:10:27 +01:00
parent ba5eca7d8e
commit ae5cebe7d7
7 changed files with 52 additions and 18 deletions

View file

@ -114,23 +114,33 @@ class SearchController < ApplicationController
end end
def quick def quick
results = [ results = if params[:filter].present?
Project.first, object_quick_search(params[:filter].singularize,
Experiment.first, search_by_id: Constants::QUICK_SEARCH_SEARCHABLE_BY_NAME
MyModule.first, .exclude?(params[:filter].singularize))
Protocol.first, else
RepositoryRow.first, Constants::QUICK_SEARCH_SEARCHABLE_OBJECTS.filter_map do |object|
Result.first, next if object == 'label_template' && !LabelTemplate.enabled?
Step.first,
Report.first, object_quick_search(object, search_by_id: Constants::QUICK_SEARCH_SEARCHABLE_BY_NAME.exclude?(object))
LabelTemplate.first end.flatten.sort_by(&:updated_at).reverse.take(Constants::QUICK_SEARCH_LIMIT)
].compact end
render json: results, each_serializer: QuickSearchSerializer render json: results, each_serializer: QuickSearchSerializer
end end
private private
def object_quick_search(class_name, search_by_id: true)
search_method = class_name.to_s.camelize.constantize.method(search_by_id ? :search_by_name_and_id : :search_by_name)
search_method.call(current_user,
current_team,
params[:query],
limit: Constants::QUICK_SEARCH_LIMIT)
.order(updated_at: :desc)
end
def load_vars def load_vars
query = (params.fetch(:q) { '' }).strip query = (params.fetch(:q) { '' }).strip
@search_category = params[:category] || '' @search_category = params[:category] || ''

View file

@ -171,7 +171,9 @@ export default {
const breadcrumbs = attributes.breadcrumbs.map((breadcrumb) => breadcrumb.name); const breadcrumbs = attributes.breadcrumbs.map((breadcrumb) => breadcrumb.name);
breadcrumbs.pop(); breadcrumbs.pop();
breadcrumbs.shift(); breadcrumbs.shift();
breadcrumbs.push(`ID: ${attributes.code}`); if (attributes.code) {
breadcrumbs.push(`ID: ${attributes.code}`);
}
return breadcrumbs; return breadcrumbs;
}, },
setQuery(query) { setQuery(query) {

View file

@ -20,10 +20,10 @@ module SearchableByNameModel
sql_q = sql_q.where(id: viewable_by_user(user, teams)) sql_q = sql_q.where(id: viewable_by_user(user, teams))
sql_q.limit(Constants::SEARCH_LIMIT) sql_q.limit(options[:limit] || Constants::SEARCH_LIMIT)
end end
def self.search_by_name_and_id(user, teams = [], query = nil) def self.search_by_name_and_id(user, teams = [], query = nil, options = {})
return if user.blank? || teams.blank? return if user.blank? || teams.blank?
sanitized_query = ActiveRecord::Base.sanitize_sql_like(query.to_s) sanitized_query = ActiveRecord::Base.sanitize_sql_like(query.to_s)
@ -34,7 +34,7 @@ module SearchableByNameModel
"%#{sanitized_query}%", "%#{sanitized_query}%" "%#{sanitized_query}%", "%#{sanitized_query}%"
) )
sql_q.limit(Constants::SEARCH_LIMIT) sql_q.limit(options[:limit] || Constants::SEARCH_LIMIT)
end end
end end
# rubocop:enable Metrics/BlockLength # rubocop:enable Metrics/BlockLength

View file

@ -2,6 +2,7 @@
class LabelTemplate < ApplicationRecord class LabelTemplate < ApplicationRecord
include SearchableModel include SearchableModel
include SearchableByNameModel
belongs_to :team belongs_to :team
belongs_to :created_by, class_name: 'User', optional: true belongs_to :created_by, class_name: 'User', optional: true
@ -17,6 +18,17 @@ class LabelTemplate < ApplicationRecord
scope :default, -> { where(default: true) } scope :default, -> { where(default: true) }
def self.viewable_by_user(user, teams)
joins("INNER JOIN user_assignments team_user_assignments
ON team_user_assignments.assignable_id = label_templates.team_id
AND team_user_assignments.assignable_type = 'Team'
AND team_user_assignments.user_id = #{user.id}
INNER JOIN user_roles team_user_roles
ON team_user_roles.id = team_user_assignments.user_role_id
AND team_user_roles.permissions @> ARRAY['#{TeamPermissions::LABEL_TEMPLATES_READ}']::varchar[]")
.where(team: teams)
end
def self.enabled? def self.enabled?
ApplicationSettings.instance.values['label_templates_enabled'] == true ApplicationSettings.instance.values['label_templates_enabled'] == true
end end

View file

@ -33,6 +33,12 @@ class ProjectFolder < ApplicationRecord
scope :top_level, -> { where(parent_folder: nil) } scope :top_level, -> { where(parent_folder: nil) }
def self.viewable_by_user(user, teams)
joins(team: :users)
.where(teams: { user_assignments: { user: user } })
.where(team: teams)
end
def self.search(user, _include_archived, query = nil, page = 1, current_team = nil, options = {}) def self.search(user, _include_archived, query = nil, page = 1, current_team = nil, options = {})
new_query = if current_team new_query = if current_team
current_team.project_folders.where_attributes_like(:name, query, options) current_team.project_folders.where_attributes_like(:name, query, options)

View file

@ -13,9 +13,7 @@ class QuickSearchSerializer < ActiveModel::Serializer
end end
def code def code
@object.code @object.code unless @object.is_a?(ProjectFolder) || object.is_a?(Result) || object.is_a?(LabelTemplate)
rescue StandardError
@object.id
end end
def updated_at def updated_at

View file

@ -443,6 +443,12 @@ class Constants
MIN_SCINOTE_EDIT_VERSION = ENV['MIN_SCINOTE_EDIT_VERSION'].freeze MIN_SCINOTE_EDIT_VERSION = ENV['MIN_SCINOTE_EDIT_VERSION'].freeze
MAX_SCINOTE_EDIT_VERSION = ENV['MAX_SCINOTE_EDIT_VERSION'].freeze MAX_SCINOTE_EDIT_VERSION = ENV['MAX_SCINOTE_EDIT_VERSION'].freeze
# quick search
QUICK_SEARCH_LIMIT = 5
QUICK_SEARCH_SEARCHABLE_OBJECTS = %w(project experiment my_module protocol repository_row
report project_folder result label_template).freeze
QUICK_SEARCH_SEARCHABLE_BY_NAME = %w(project_folder result label_template).freeze
# ) \ / ( # ) \ / (
# /|\ )\_/( /|\ # /|\ )\_/( /|\
# * / | \ (/\|/\) / | \ * # * / | \ (/\|/\) / | \ *