Merge pull request #9363 from demarches-simplifiees/dashboard-usager/make-search-work-with-procedure-filter

[refonte usager] Tableau de bord - rendre recherche complémentaire avec filtre par procédure
This commit is contained in:
Lisa Durand 2023-09-13 12:55:42 +00:00 committed by GitHub
commit 7311bcebb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 64 deletions

View file

@ -1,4 +1,5 @@
= form_with(url: dossiers_path, method: :get, data: { controller: 'autosubmit' } ) do |f|
= f.hidden_field :q, value: params[:q], id: nil
= f.label :procedure_id, t('.procedure.label'), class: 'sr-only'
.fr-input-group
= f.select :procedure_id, options_for_select(@procedures_for_select, params[:procedure_id]), { prompt: t('.procedures.prompt') }, class: 'fr-select'

View file

@ -5,7 +5,7 @@ module Users
layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret]
ACTIONS_ALLOWED_TO_ANY_USER = [:index, :recherche, :new, :transferer_all]
ACTIONS_ALLOWED_TO_ANY_USER = [:index, :new, :transferer_all]
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :destroy, :demande, :messagerie, :brouillon, :submit_brouillon, :submit_en_construction, :modifier, :modifier_legacy, :update, :create_commentaire, :papertrail, :restore, :champ]
before_action :ensure_ownership!, except: ACTIONS_ALLOWED_TO_ANY_USER + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE
@ -33,21 +33,28 @@ module Users
.distinct(:procedure_id)
.order(:libelle)
.pluck(:libelle, :id)
@procedure_id = params[:procedure_id]
@procedure_id = params[:procedure_id]
if @procedure_id.present?
ordered_dossiers = ordered_dossiers.where(procedures: { id: @procedure_id })
deleted_dossiers = deleted_dossiers.where(procedures: { id: @procedure_id })
end
dossiers_visibles = ordered_dossiers.visible_by_user
@search_terms = params[:q]
if @search_terms.present?
dossiers_filter_by_search = DossierSearchService.matching_dossiers_for_user(@search_terms, current_user).page
ordered_dossiers = ordered_dossiers.merge(dossiers_filter_by_search)
deleted_dossiers = nil
end
@user_dossiers = current_user.dossiers.state_not_termine.merge(dossiers_visibles)
@dossiers_traites = current_user.dossiers.state_termine.merge(dossiers_visibles)
@dossiers_invites = current_user.dossiers_invites.merge(dossiers_visibles)
@dossiers_visibles = ordered_dossiers.visible_by_user
@user_dossiers = current_user.dossiers.state_not_termine.merge(@dossiers_visibles)
@dossiers_traites = current_user.dossiers.state_termine.merge(@dossiers_visibles)
@dossiers_invites = current_user.dossiers_invites.merge(@dossiers_visibles)
@dossiers_supprimes_recemment = current_user.dossiers.hidden_by_user.merge(ordered_dossiers)
@dossier_transferes = dossiers_visibles.where(dossier_transfer_id: DossierTransfer.for_email(current_user.email).ids)
@dossiers_close_to_expiration = current_user.dossiers.close_to_expiration.merge(dossiers_visibles)
@dossier_transferes = @dossiers_visibles.where(dossier_transfer_id: DossierTransfer.for_email(current_user.email).ids)
@dossiers_close_to_expiration = current_user.dossiers.close_to_expiration.merge(@dossiers_visibles)
@dossiers_supprimes_definitivement = deleted_dossiers
@statut = statut(@user_dossiers, @dossiers_traites, @dossiers_invites, @dossiers_supprimes_recemment, @dossiers_supprimes_definitivement, @dossier_transferes, @dossiers_close_to_expiration, params[:statut])
@ -337,28 +344,6 @@ module Users
end
end
def recherche
@procedures_for_select = nil
@search_terms = params[:q]
return redirect_to dossiers_path if @search_terms.blank?
@dossiers = DossierSearchService.matching_dossiers_for_user(@search_terms, current_user).page(page)
if @dossiers.present?
# we need the page condition when accessing page n with n>1 when the page has only 1 result
# in order to avoid an unpleasant redirection when changing page
if @dossiers.count == 1 && page == 1
redirect_to url_for_dossier(@dossiers.first)
else
render :index
end
else
flash.alert = "Vous navez pas de dossiers contenant « #{@search_terms} »."
redirect_to dossiers_path
end
end
def new
erase_user_location!

View file

@ -10,7 +10,7 @@ class DossierSearchService
def self.matching_dossiers_for_user(search_terms, user)
dossier_by_exact_id_for_user(search_terms, user)
.presence || dossier_by_full_text_for_user(search_terms, Dossier.where(id: user.dossiers.ids + user.dossiers_invites.ids))
.presence || dossier_by_full_text_for_user(search_terms, Dossier.includes(:procedure).where(id: user.dossiers.ids + user.dossiers_invites.ids))
end
private
@ -38,7 +38,7 @@ class DossierSearchService
def self.dossier_by_full_text_for_user(search_terms, dossiers)
ts_vector = "to_tsvector('french', search_terms)"
ts_query = "to_tsquery('french', #{Dossier.connection.quote(to_tsquery(search_terms))})"
ts_query = "to_tsquery('french', #{Dossier.includes(:procedure).connection.quote(to_tsquery(search_terms))})"
dossiers
.visible_by_user
@ -49,9 +49,9 @@ class DossierSearchService
def self.dossier_by_exact_id_for_user(search_terms, user)
id = search_terms.to_i
if id != 0 && id_compatible?(id) # Sometimes user is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this.
Dossier.where(id: user.dossiers.visible_by_user.where(id: id) + user.dossiers_invites.visible_by_user.where(id: id)).distinct
Dossier.includes(:procedure).where(id: user.dossiers.visible_by_user.where(id: id) + user.dossiers_invites.visible_by_user.where(id: id)).distinct
else
Dossier.none
Dossier.includes(:procedure).none
end
end

View file

@ -94,7 +94,7 @@
- else
- if filter.filter_params.present?
- if filter.present?
.blank-tab
%h2.empty-text= t('views.users.dossiers.dossiers_list.no_result_title')
%p.empty-text-details
@ -102,6 +102,13 @@
%br
= link_to t('views.users.dossiers.dossiers_list.no_result_reset_filter'), dossiers_path(statut: statut), class: 'fr-btn fr-btn--sm fr-mt-2w'
- elsif search
.blank-tab
%h2.empty-text= t('views.users.dossiers.dossiers_list.no_result_title')
%p.empty-text-details
= t('views.users.dossiers.dossiers_list.no_result_text_with_search')
%br
= link_to t('views.users.dossiers.dossiers_list.no_result_reset_search'), dossiers_path(), class: 'fr-btn fr-btn--sm fr-mt-2w'
- else
.blank-tab
%h2.empty-text= t('views.users.dossiers.dossiers_list.no_result_title')

View file

@ -14,7 +14,8 @@
- if current_user.dossiers.count > 2 || current_user.dossiers_invites.count > 2
.fr-col
#search-2.fr-search-bar
= form_tag recherche_dossiers_path, method: :get, :role => "search", class: "flex width-100 fr-mb-5w" do
= form_tag dossiers_path, method: :get, :role => "search", class: "flex width-100 fr-mb-5w" do
= hidden_field_tag :procedure_id, params[:procedure_id]
= label_tag "q", t('views.users.dossiers.search.search_file'), class: 'fr-label'
= text_field_tag "q", "#{@search_terms if @search_terms.present?}", placeholder: t('views.users.dossiers.search.search_file'), class: "fr-input"
%button.fr-btn.fr-btn--sm
@ -71,7 +72,7 @@
.fr-container
.fr-grid-row.fr-grid-row--center
.fr-col-xl-10
- if @statut == "en-cours"
- if @statut == "en-cours" && @search_terms.blank?
- if @first_brouillon_recently_updated.present?
= render Dsfr::CalloutComponent.new(title: t('users.dossiers.header.callout.first_brouillon_recently_updated_title'), heading_level: 'h2') do |c|
- c.with_body do
@ -80,8 +81,11 @@
= link_to t('users.dossiers.header.callout.first_brouillon_recently_updated_button'), url_for_dossier(@first_brouillon_recently_updated), class: 'fr-btn'
- if @search_terms.present?
%h2.page-title Résultat de la recherche pour « #{@search_terms} »
= render partial: "dossiers_list", locals: { dossiers: @dossiers }
%h2.page-title
= t('views.users.dossiers.search.result_term_title', search_terms: @search_terms)
- if @procedure_id.present?
= t('views.users.dossiers.search.result_procedure_title', procedure_libelle: @procedures_for_select.rassoc(@procedure_id.to_i).first)
= render partial: "dossiers_list", locals: { dossiers: @dossiers_visibles, filter: nil, search: true }
- else
= render Dossiers::UserFilterComponent.new(statut: @statut, filter: @filter, procedure_id: @procedure_id )
@ -90,4 +94,4 @@
-# /!\ in this context, @dossiers is a collection of DeletedDossier not Dossier
= render partial: "deleted_dossiers_list", locals: { deleted_dossiers: @dossiers }
- else
= render partial: "dossiers_list", locals: { dossiers: @dossiers, filter: @filter, statut: @statut }
= render partial: "dossiers_list", locals: { dossiers: @dossiers, filter: @filter, statut: @statut, search: false }

View file

@ -471,6 +471,8 @@ en:
search:
search_file: Search a file (File number, keywords)
simple: Search
result_term_title: Search result for « %{search_terms} »
result_procedure_title: and procedure « %{procedure_libelle} »
secondary_menu: Secondary menu
index:
dossiers: "My files"
@ -478,6 +480,8 @@ en:
n_dossier: "File n."
no_result_title: No files
no_result_text_html: "To fill a procedure, contact your administration asking for the procedure link. <br> It should look like %{app_base}/commencer/xxx."
no_result_text_with_search: found with search terms
no_result_reset_search: Reset search
no_result_text_with_filter: found with selected filters
no_result_reset_filter: Reset filters
procedure_closed: This procedure has been closed, you will not be able to submit a file again from the procedure link, contact your administration for more information.

View file

@ -473,6 +473,8 @@ fr:
search:
search_file: Rechercher un dossier (N° de dossier, mots-clés)
simple: Rechercher
result_term_title: Résultat de la recherche pour « %{search_terms} »
result_procedure_title: et pour la procédure « %{procedure_libelle} »
secondary_menu: Menu secondaire
index:
dossiers: "Mes dossiers"
@ -480,6 +482,8 @@ fr:
n_dossier: "dossier Nº "
no_result_title: Aucun dossier
no_result_text_html: "Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche. <br> Celui ci doit ressembler à %{app_base}/commencer/xxx."
no_result_text_with_search: ne correspond aux termes recherchés
no_result_reset_search: Réinitialiser la recherche
no_result_text_with_filter: ne correspond aux filtres sélectionnés
no_result_reset_filter: Réinitialiser les filtres
procedure_closed: Cette démarche a été clôturée, vous ne pourrez pas redéposer de dossier à partir du lien de la démarche, contactez votre administration pour plus dinformation.

View file

@ -331,7 +331,6 @@ Rails.application.routes.draw do
collection do
get 'transferer', to: 'dossiers#transferer_all'
get 'recherche'
resources :transfers, only: [:create, :update, :destroy]
end
end

View file

@ -164,16 +164,18 @@ describe 'Invitations' do
visit dossiers_path
end
it "can search by id and it redirects to the dossier page" do
it "can search by id and it displays the dossier" do
page.find_by_id('q').set(dossier.id)
find('.fr-search-bar .fr-btn').click
expect(current_path).to eq(dossier_path(dossier))
expect(current_path).to eq(dossiers_path)
expect(page).to have_link(dossier.procedure.libelle)
end
it "can search something inside the dossier and it redirects to the dossier page" do
it "can search something inside the dossier and it displays the dossier" do
page.find_by_id('q').set(dossier_2.champs_public.first.value)
find('.fr-search-bar .fr-btn').click
expect(current_path).to eq(dossier_path(dossier_2))
expect(current_path).to eq(dossiers_path)
expect(page).to have_link(dossier.procedure.libelle)
end
end
end

View file

@ -190,7 +190,7 @@ describe 'user access to the list of their dossiers', js: true, retry: 3 do
end
end
describe "recherche" do
describe "user search bar" do
context "when the dossier does not exist" do
before do
page.find_by_id('q').set(10000000)
@ -199,7 +199,9 @@ describe 'user access to the list of their dossiers', js: true, retry: 3 do
it "shows an error message on the dossiers page" do
expect(current_path).to eq(dossiers_path)
expect(page).to have_content("Vous navez pas de dossiers contenant « 10000000 ».")
expect(page).to have_content("Résultat de la recherche pour « 10000000 »")
expect(page).to have_content("Aucun dossier")
expect(page).to have_content("ne correspond aux termes recherchés")
end
end
@ -213,7 +215,10 @@ describe 'user access to the list of their dossiers', js: true, retry: 3 do
it "shows an error message on the dossiers page" do
expect(current_path).to eq(dossiers_path)
expect(page).to have_content("Vous navez pas de dossiers contenant « #{dossier_other_user.id} ».")
expect(page).to have_content("Résultat de la recherche pour « #{dossier_other_user.id} »")
expect(page).to have_content("Aucun dossier")
expect(page).to have_content("ne correspond aux termes recherchés")
expect(page).to have_content("Réinitialiser la recherche")
end
end
@ -223,8 +228,11 @@ describe 'user access to the list of their dossiers', js: true, retry: 3 do
find('.fr-search-bar .fr-btn').click
end
it "redirects to the dossier page" do
expect(current_path).to eq(dossier_path(dossier_en_construction))
it "appears in the result list" do
expect(current_path).to eq(dossiers_path)
expect(page).to have_content("Résultat de la recherche pour « #{dossier_en_construction.id} »")
expect(page).not_to have_css('.tabs')
expect(page).to have_content(dossier_en_construction.id)
end
end
@ -233,25 +241,32 @@ describe 'user access to the list of their dossiers', js: true, retry: 3 do
page.find_by_id('q').set(dossier_en_construction.champs_public.first.value)
end
context 'when it only matches one dossier' do
before do
find('.fr-search-bar .fr-btn').click
end
it "redirects to the dossier page" do
expect(current_path).to eq(dossier_path(dossier_en_construction))
end
end
context 'when it matches multiple dossier' do
context 'when it matches multiple dossiers' do
let!(:dossier_with_champs) { create(:dossier, :with_populated_champs, :en_construction, user: user) }
before do
find('.fr-search-bar .fr-btn').click
end
it "redirects to the search results" do
expect(current_path).to eq(recherche_dossiers_path)
expect(page).to have_content(dossier_en_construction.id)
expect(page).to have_content(dossier_with_champs.id)
it "appears in the result list" do
expect(current_path).to eq(dossiers_path)
expect(page).to have_link(dossier_en_construction.procedure.libelle)
expect(page).to have_link(dossier_with_champs.procedure.libelle)
expect(page).to have_text("2 sur 2 dossiers")
end
it "can be filtered by procedure and display the result - one item" do
select dossier_en_construction.procedure.libelle, from: 'procedure_id'
expect(page).to have_link(dossier_en_construction.procedure.libelle)
expect(page).not_to have_link(dossier_with_champs.procedure.libelle)
expect(page).to have_text("1 dossier")
end
it "can be filtered by procedure and display the result - no item" do
select dossier_brouillon.procedure.libelle, from: 'procedure_id'
expect(page).not_to have_link(dossier_en_construction.id)
expect(page).not_to have_link(dossier_with_champs.id)
expect(page).to have_content("Résultat de la recherche pour « #{dossier_en_construction.champs_public.first.value} » et pour la procédure « #{dossier_brouillon.procedure.libelle} » ")
expect(page).to have_text("Aucun dossier")
end
end
end