Merge pull request #10898 from mfo/US/navigation-accros-dossiers
ETQ instructeur, je peux passer au dossiers suivant ou au dossier précédent lorsque je visualise un dossiers d'un des onglet (a-suivre, tous, ...)
This commit is contained in:
commit
6e5aa90bc7
31 changed files with 434 additions and 30 deletions
|
@ -397,3 +397,7 @@ ul.dropdown-items {
|
|||
content: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ class Instructeurs::BackButtonComponent < ApplicationComponent
|
|||
end
|
||||
|
||||
def call
|
||||
link_to "", @to, class: 'back-btn fr-btn fr-btn--secondary fr-btn--sm fr-mr-2w fr-icon-arrow-left-line', title: t('.back')
|
||||
link_to @to, class: 'back-btn fr-btn fr-btn--secondary fr-btn--sm fr-mr-2w fr-px-1v', title: t('.back') do
|
||||
dsfr_icon("fr-icon-arrow-left-line")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
45
app/components/instructeurs/dossiers_navigation_component.rb
Normal file
45
app/components/instructeurs/dossiers_navigation_component.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Instructeurs::DossiersNavigationComponent < ApplicationComponent
|
||||
attr_reader :dossier, :statut
|
||||
|
||||
def initialize(dossier:, procedure_presentation:, statut:)
|
||||
@dossier = dossier
|
||||
@cache = Cache::ProcedureDossierPagination.new(procedure_presentation: procedure_presentation, statut:)
|
||||
@statut = statut
|
||||
end
|
||||
|
||||
def back_url_options
|
||||
options = { statut: }
|
||||
options = options.merge(page: @cache.incoming_page) if @cache.incoming_page
|
||||
options
|
||||
end
|
||||
|
||||
def link_next
|
||||
if has_next?
|
||||
html_tag = :a
|
||||
options = { class: "fr-link no-wrap fr-ml-3w", href: next_instructeur_dossier_path(dossier:, statut:) }
|
||||
else
|
||||
html_tag = :span
|
||||
options = { class: "fr-link no-wrap fr-ml-3w fr-text-mention--grey" }
|
||||
end
|
||||
|
||||
tag.send(html_tag, t('.next').html_safe + tag.span(class: 'fr-icon-arrow-right-line fr-ml-1w'), **options)
|
||||
end
|
||||
|
||||
def link_previous
|
||||
if has_previous?
|
||||
html_tag = :a
|
||||
options = { class: "fr-link no-wrap", href: previous_instructeur_dossier_path(dossier:, statut:) }
|
||||
else
|
||||
html_tag = :span
|
||||
options = { class: "fr-link no-wrap fr-text-mention--grey" }
|
||||
end
|
||||
|
||||
tag.send(html_tag, tag.span(class: 'fr-icon-arrow-left-line fr-mr-1w') + t('.previous'), **options)
|
||||
end
|
||||
|
||||
def has_next? = @has_next ||= @cache.next_dossier_id(from_id: dossier.id).present?
|
||||
|
||||
def has_previous? = @has_previous ||= @cache.previous_dossier_id(from_id: dossier.id).present?
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
en:
|
||||
next: Next file
|
||||
previous: Previous file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fr:
|
||||
next: Dossier suivant
|
||||
previous: Dossier précédent
|
|
@ -0,0 +1,11 @@
|
|||
.flex.fr-mb-1w.align-start
|
||||
= render Instructeurs::BackButtonComponent.new(to: instructeur_procedure_path(dossier.procedure, **back_url_options))
|
||||
|
||||
%h1.fr-h3.fr-mb-0
|
||||
= t('show_dossier', scope: [:layouts, :breadcrumb], dossier_id: dossier.id, owner_name: dossier.owner_name)
|
||||
|
||||
.fr.ml-auto.align-center.flex.fr-mt-1v
|
||||
= link_previous
|
||||
= link_next
|
||||
|
||||
= link_to dossier.procedure.libelle.truncate_words(10), instructeur_procedure_path(dossier.procedure), title: dossier.procedure.libelle, class: "fr-link"
|
11
app/controllers/concerns/instructeur_concern.rb
Normal file
11
app/controllers/concerns/instructeur_concern.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module InstructeurConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
def retrieve_procedure_presentation
|
||||
@procedure_presentation ||= current_instructeur.procedure_presentation_for_procedure_id(params[:procedure_id])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
module Instructeurs
|
||||
class CommentairesController < ApplicationController
|
||||
include InstructeurConcern
|
||||
before_action :authenticate_instructeur_or_expert!
|
||||
after_action :mark_messagerie_as_read
|
||||
|
||||
def destroy
|
||||
retrieve_procedure_presentation if current_instructeur
|
||||
if commentaire.sent_by?(current_instructeur) || commentaire.sent_by?(current_expert)
|
||||
commentaire.soft_delete!
|
||||
|
||||
|
|
|
@ -7,15 +7,16 @@ module Instructeurs
|
|||
include CreateAvisConcern
|
||||
include DossierHelper
|
||||
include TurboChampsConcern
|
||||
|
||||
include InstructeurConcern
|
||||
include ActionController::Streaming
|
||||
include Zipline
|
||||
|
||||
before_action :redirect_on_dossier_not_found, only: :show
|
||||
before_action :redirect_on_dossier_in_batch_operation, only: [:archive, :unarchive, :follow, :unfollow, :passer_en_instruction, :repasser_en_construction, :repasser_en_instruction, :terminer, :restore, :destroy, :extend_conservation]
|
||||
before_action :set_gallery_attachments, only: [:show, :pieces_jointes, :annotations_privees, :avis, :messagerie, :personnes_impliquees, :reaffectation]
|
||||
after_action :mark_demande_as_read, only: :show
|
||||
before_action :retrieve_procedure_presentation, only: [:annotations_privees, :avis_new, :avis, :messagerie, :personnes_impliquees, :pieces_jointes, :reaffectation, :show, :dossier_labels, :passer_en_instruction, :repasser_en_construction, :repasser_en_instruction, :terminer, :pending_correction, :create_avis, :create_commentaire]
|
||||
|
||||
after_action :mark_demande_as_read, only: :show
|
||||
after_action :mark_messagerie_as_read, only: [:messagerie, :create_commentaire, :pending_correction]
|
||||
after_action :mark_avis_as_read, only: [:avis, :create_avis]
|
||||
after_action :mark_annotations_privees_as_read, only: [:annotations_privees, :update_annotations]
|
||||
|
@ -390,8 +391,40 @@ module Instructeurs
|
|||
@pieces_jointes_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.pieces_jointes_seen_at
|
||||
end
|
||||
|
||||
def next
|
||||
navigate_through_dossiers_list do |cache|
|
||||
cache.next_dossier_id(from_id: params[:dossier_id])
|
||||
end
|
||||
end
|
||||
|
||||
def previous
|
||||
navigate_through_dossiers_list do |cache|
|
||||
cache.previous_dossier_id(from_id: params[:dossier_id])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def navigate_through_dossiers_list
|
||||
dossier = dossier_scope.find(params[:dossier_id])
|
||||
procedure_presentation = current_instructeur.procedure_presentation_for_procedure_id(dossier.procedure.id)
|
||||
cache = Cache::ProcedureDossierPagination.new(procedure_presentation:, statut: params[:statut])
|
||||
|
||||
next_or_previous_dossier_id = yield(cache)
|
||||
|
||||
if next_or_previous_dossier_id
|
||||
redirect_to instructeur_dossier_path(procedure_id: procedure.id, dossier_id: next_or_previous_dossier_id, statut: params[:statut])
|
||||
else
|
||||
redirect_back fallback_location: instructeur_dossier_path(procedure_id: procedure.id, dossier_id: dossier.id, statut: params[:statut]), alert: "Une erreur est survenue"
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
Sentry.capture_message(
|
||||
"Navigation through dossier failed => ActiveRecord::RecordNotFound",
|
||||
extra: { dossier_id: params[:dossier_id] }
|
||||
)
|
||||
redirect_to instructeur_procedure_path(procedure_id: procedure.id), alert: "Une erreur est survenue"
|
||||
end
|
||||
|
||||
def dossier_scope
|
||||
if action_name == 'update_annotations'
|
||||
Dossier
|
||||
|
|
|
@ -122,6 +122,8 @@ module Instructeurs
|
|||
.where(groupe_instructeurs: current_instructeur.groupe_instructeurs.where(procedure_id: @procedure.id))
|
||||
.where(seen_at: nil)
|
||||
.distinct
|
||||
|
||||
cache_show_procedure_state # don't move in callback, inherited by Instructeurs::DossiersController
|
||||
end
|
||||
|
||||
def deleted_dossiers
|
||||
|
@ -392,5 +394,11 @@ module Instructeurs
|
|||
def ordered_procedure_ids_params
|
||||
params.require(:ordered_procedure_ids)
|
||||
end
|
||||
|
||||
def cache_show_procedure_state
|
||||
cache = Cache::ProcedureDossierPagination.new(procedure_presentation:, statut:)
|
||||
|
||||
cache.save_context(ids: @filtered_sorted_paginated_ids, incoming_page: params[:page])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
102
app/models/cache/procedure_dossier_pagination.rb
vendored
Normal file
102
app/models/cache/procedure_dossier_pagination.rb
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Cache::ProcedureDossierPagination
|
||||
HALF_WINDOW = 50
|
||||
TRESHOLD_BEFORE_REFRESH = 1
|
||||
CACHE_EXPIRACY = 8.hours
|
||||
|
||||
attr_reader :procedure_presentation, :statut, :cache
|
||||
delegate :procedure, :instructeur, to: :procedure_presentation
|
||||
|
||||
def initialize(procedure_presentation:, statut:)
|
||||
@procedure_presentation = procedure_presentation
|
||||
@statut = statut
|
||||
@cache = Kredis.json(cache_key, expires_in: CACHE_EXPIRACY)
|
||||
end
|
||||
|
||||
def save_context(ids:, incoming_page:)
|
||||
value = { ids: }
|
||||
value[:incoming_page] = incoming_page if incoming_page
|
||||
write_cache(value)
|
||||
end
|
||||
|
||||
def next_dossier_id(from_id:)
|
||||
index = ids&.index(from_id.to_i)
|
||||
|
||||
return nil if index.nil? # not found
|
||||
|
||||
if refresh_cache_after?(from_id:)
|
||||
renew_ids(from_id:)
|
||||
index = ids.index(from_id.to_i)
|
||||
end
|
||||
return nil if index.blank?
|
||||
return nil if index + 1 > ids.size # out of bound end
|
||||
|
||||
ids[index + 1]
|
||||
end
|
||||
|
||||
def previous_dossier_id(from_id:)
|
||||
index = ids&.index(from_id.to_i)
|
||||
|
||||
return nil if index.nil? # not found
|
||||
|
||||
if refresh_cache_before?(from_id:)
|
||||
renew_ids(from_id:)
|
||||
index = ids.index(from_id.to_i)
|
||||
end
|
||||
return nil if index.blank?
|
||||
return nil if index - 1 < 0 # out of bound start
|
||||
|
||||
ids[index - 1]
|
||||
end
|
||||
|
||||
def incoming_page
|
||||
read_cache[:incoming_page]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cache_key
|
||||
[procedure.id, instructeur.id, statut].join(":")
|
||||
end
|
||||
|
||||
def write_cache(value)
|
||||
cache.value = value
|
||||
@read_cache = nil
|
||||
end
|
||||
|
||||
def read_cache
|
||||
@read_cache ||= Hash(cache.value).with_indifferent_access
|
||||
end
|
||||
|
||||
def ids = read_cache[:ids]
|
||||
|
||||
def refresh_cache_after?(from_id:) = from_id.in?(ids.last(TRESHOLD_BEFORE_REFRESH))
|
||||
|
||||
def refresh_cache_before?(from_id:) = from_id.in?(ids.first(TRESHOLD_BEFORE_REFRESH))
|
||||
|
||||
def renew_ids(from_id:)
|
||||
value = read_cache
|
||||
value[:ids] = fetch_ids_around(from_id:)
|
||||
|
||||
write_cache(value)
|
||||
end
|
||||
|
||||
def fetch_all_ids
|
||||
dossiers = Dossier.where(groupe_instructeur_id: GroupeInstructeur.joins(:instructeurs, :procedure).where(procedure: procedure, instructeurs: [instructeur]).select(:id))
|
||||
DossierFilterService.filtered_sorted_ids(dossiers, statut, procedure_presentation.filters_for(statut), procedure_presentation.sorted_column, instructeur, count: 0)
|
||||
end
|
||||
|
||||
def fetch_ids_around(from_id:)
|
||||
all_ids = fetch_all_ids
|
||||
from_id_at = all_ids.index(from_id)
|
||||
|
||||
if from_id_at.present?
|
||||
new_page_starts_at = [0, from_id_at - HALF_WINDOW].max # avoid index below 0
|
||||
new_page_ends_at = [from_id_at + HALF_WINDOW, all_ids.size].min # avoid index above all_ids.size
|
||||
all_ids.slice(new_page_starts_at, new_page_ends_at)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -127,12 +127,14 @@ class Instructeur < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def procedure_presentation_for_procedure_id(procedure_id)
|
||||
assign_to = assign_to_for_procedure_id(procedure_id)
|
||||
assign_to.procedure_presentation || assign_to.create_procedure_presentation!
|
||||
end
|
||||
|
||||
def procedure_presentation_and_errors_for_procedure_id(procedure_id)
|
||||
assign_to
|
||||
.joins(:groupe_instructeur)
|
||||
.includes(:instructeur, :procedure)
|
||||
.find_by(groupe_instructeurs: { procedure_id: procedure_id })
|
||||
.procedure_presentation_or_default_and_errors
|
||||
assign_to = assign_to_for_procedure_id(procedure_id)
|
||||
assign_to.procedure_presentation_or_default_and_errors
|
||||
end
|
||||
|
||||
def notifications_for_dossier(dossier)
|
||||
|
@ -355,4 +357,11 @@ class Instructeur < ApplicationRecord
|
|||
.merge(followed_dossiers)
|
||||
.with_notifications
|
||||
end
|
||||
|
||||
def assign_to_for_procedure_id(procedure_id)
|
||||
assign_to
|
||||
.joins(:groupe_instructeur)
|
||||
.includes(:instructeur, :procedure)
|
||||
.find_by(groupe_instructeurs: { procedure_id: procedure_id })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
= render Dossiers::MessageComponent.new(commentaire: @commentaire, connected_user: @commentaire.instructeur || @commentaire.expert)
|
||||
|
||||
- if current_user.instructeur? && @commentaire.dossier_correction.present?
|
||||
= turbo_stream.replace 'header-top', partial: 'instructeurs/dossiers/header_top', locals: { dossier: @commentaire.dossier }
|
||||
= turbo_stream.replace 'header-top', partial: 'instructeurs/dossiers/header_top', locals: { dossier: @commentaire.dossier, procedure_presentation: @procedure_presentation }
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
locals: { steps: [[t('show_procedure', scope: [:layouts, :breadcrumb], libelle: dossier.procedure.libelle.truncate(22)), instructeur_procedure_path(dossier.procedure)],
|
||||
[t('show_dossier', scope: [:layouts, :breadcrumb], dossier_id: dossier.id, owner_name: dossier.owner_name)]] }
|
||||
|
||||
= render partial: 'instructeurs/dossiers/header_top', locals: { dossier: }
|
||||
= render partial: 'instructeurs/dossiers/header_top', locals: { dossier:, procedure_presentation: }
|
||||
= render partial: 'instructeurs/dossiers/header_bottom', locals: { dossier:, gallery_attachments: }
|
||||
|
||||
.fr-container
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
#header-top.fr-container
|
||||
.flex
|
||||
= render Instructeurs::DossiersNavigationComponent.new(dossier:, procedure_presentation:, statut: params[:statut])
|
||||
|
||||
.flex.fr-mb-3w
|
||||
%div
|
||||
.flex.fr-mb-1w
|
||||
= render Instructeurs::BackButtonComponent.new(to: instructeur_procedure_path(dossier.procedure, statut: params[:statut]))
|
||||
%h1.fr-h3.fr-mb-1w
|
||||
= t('show_dossier', scope: [:layouts, :breadcrumb], dossier_id: dossier.id, owner_name: dossier.owner_name)
|
||||
|
||||
|
||||
= link_to dossier.procedure.libelle.truncate_words(10), instructeur_procedure_path(dossier.procedure), title: dossier.procedure.libelle, class: "fr-link"
|
||||
.fr-mt-2w.fr-badge-group
|
||||
.fr-mt-2w.badge-group
|
||||
= procedure_badge(dossier.procedure)
|
||||
|
||||
= status_badge(dossier.state)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Annotations privées · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
#dossier-annotations-privees
|
||||
.fr-container
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Avis · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
.container
|
||||
.fr-grid-row
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Avis · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
.container
|
||||
.fr-grid-row
|
||||
|
|
|
@ -1 +1 @@
|
|||
= turbo_stream.replace 'header-top', partial: 'header_top', locals: { dossier: @dossier }
|
||||
= turbo_stream.replace 'header-top', partial: 'header_top', locals: { dossier: @dossier, procedure_presentation: @procedure_presentation }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- content_for(:title, "Messagerie · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
= render partial: "shared/dossiers/messagerie", locals: { dossier: @dossier, connected_user: current_instructeur, messagerie_seen_at: @messagerie_seen_at , new_commentaire: @commentaire, form_url: commentaire_instructeur_dossier_path(@dossier.procedure, @dossier, statut: params[:statut]) }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Personnes impliquées · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
.personnes-impliquees.container
|
||||
= render partial: 'instructeurs/dossiers/envoyer_dossier_block', locals: { dossier: @dossier, potential_recipients: @potential_recipients }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Pièces jointes")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
.fr-container
|
||||
.gallery.gallery-pieces-jointes{ "data-controller": "lightbox" }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Réaffectation · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
.container.groupe-instructeur
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- content_for(:title, "Demande · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
|
||||
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments }
|
||||
= render partial: "header", locals: { dossier: @dossier, gallery_attachments: @gallery_attachments, procedure_presentation: @procedure_presentation }
|
||||
|
||||
|
||||
- if @dossier.etablissement&.as_degraded_mode?
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.procedure-header
|
||||
.clipboard-container.flex
|
||||
.align-start.flex
|
||||
= render Instructeurs::BackButtonComponent.new(to: instructeur_procedures_path)
|
||||
%h1.fr-h3.fr-mb-0
|
||||
= "#{procedure_libelle procedure} (n°#{procedure.id})"
|
||||
|
|
|
@ -485,6 +485,8 @@ Rails.application.routes.draw do
|
|||
resources :dossiers, only: [:show, :destroy], param: :dossier_id, path: "(:statut)/dossiers", defaults: { statut: 'a-suivre' } do
|
||||
member do
|
||||
resources :commentaires, only: [:destroy]
|
||||
get 'next'
|
||||
get 'previous'
|
||||
post 'repousser-expiration' => 'dossiers#extend_conservation'
|
||||
post 'repousser-expiration-and-restore' => 'dossiers#extend_conservation_and_restore'
|
||||
post 'dossier_labels' => 'dossiers#dossier_labels'
|
||||
|
|
|
@ -984,6 +984,68 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'navigation accross next/prev dossiers' do
|
||||
let(:dossier_id) { dossier.id }
|
||||
let(:statut) { 'a-suivre' }
|
||||
let(:previous_dossier) { create(:dossier, :en_construction, procedure:) }
|
||||
let(:next_dossier) { create(:dossier, :en_construction, procedure:) }
|
||||
let(:cached_ids) { [previous_dossier, dossier, next_dossier].map(&:id) }
|
||||
before do
|
||||
cache = Cache::ProcedureDossierPagination.new(procedure_presentation: double(procedure:, instructeur:), statut:)
|
||||
cache.save_context(incoming_page: 1, ids: cached_ids)
|
||||
end
|
||||
|
||||
context 'when nexting' do
|
||||
subject { get :next, params: { procedure_id: procedure.id, dossier_id: from_id, statut: } }
|
||||
|
||||
context 'when their is a next id' do
|
||||
let(:from_id) { dossier.id }
|
||||
it { is_expected.to redirect_to(instructeur_dossier_path(procedure_id: procedure.id, dossier_id: next_dossier.id)) }
|
||||
end
|
||||
|
||||
context 'when their is not next id (en of list)' do
|
||||
let(:from_id) { cached_ids.last }
|
||||
it 'redirect on fallback location being current dossier and flashes an error' do
|
||||
expect(subject).to redirect_to(instructeur_dossier_path(procedure_id: procedure.id, dossier_id: from_id))
|
||||
expect(flash.alert).to eq("Une erreur est survenue")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when id does not exists' do
|
||||
let(:from_id) { 'kthxbye' }
|
||||
it 'redirect on fallback location being current dossier and flashes an error' do
|
||||
expect(subject).to redirect_to(instructeur_procedure_path(procedure_id: procedure.id))
|
||||
expect(flash.alert).to eq("Une erreur est survenue")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when previousing' do
|
||||
subject { get :previous, params: { procedure_id: procedure.id, dossier_id: from_id, statut: } }
|
||||
|
||||
context 'when their is a previous id' do
|
||||
let(:from_id) { dossier.id }
|
||||
it { is_expected.to redirect_to(instructeur_dossier_path(procedure_id: procedure.id, dossier_id: previous_dossier.id)) }
|
||||
end
|
||||
|
||||
context 'when their is not previous id (before list)' do
|
||||
let(:from_id) { cached_ids.first }
|
||||
it 'redirect on fallback location being current dossier and flashes an error' do
|
||||
expect(subject).to redirect_to(instructeur_dossier_path(procedure_id: procedure.id, dossier_id: from_id))
|
||||
expect(flash.alert).to eq("Une erreur est survenue")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when id does not exists' do
|
||||
let(:from_id) { 'kthxbye' }
|
||||
it 'redirect on fallback location being current dossier and flashes an error' do
|
||||
expect(subject).to redirect_to(instructeur_procedure_path(procedure_id: procedure.id))
|
||||
expect(flash.alert).to eq("Une erreur est survenue")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#update_annotations" do
|
||||
let(:procedure) do
|
||||
create(:procedure, :published, types_de_champ_public:, types_de_champ_private:, instructeurs: instructeurs)
|
||||
|
|
|
@ -670,6 +670,18 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'caches statut and page query param' do
|
||||
let(:statut) { 'tous' }
|
||||
let(:page) { '1' }
|
||||
let!(:dossier) { create(:dossier, :accepte, procedure:) }
|
||||
before { sign_in(instructeur.user) }
|
||||
subject { get :show, params: { procedure_id: procedure.id, statut:, page: } }
|
||||
it 'changes cached value' do
|
||||
expect { subject }.to change { Cache::ProcedureDossierPagination.new(statut:, procedure_presentation: double(procedure:, instructeur:)).send(:read_cache) }
|
||||
.from({}).to(ids: [dossier.id], incoming_page: page)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#deleted_dossiers' do
|
||||
|
|
86
spec/models/cache/procedure_dossier_pagination_spec.rb
vendored
Normal file
86
spec/models/cache/procedure_dossier_pagination_spec.rb
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe Cache::ProcedureDossierPagination do
|
||||
let(:instructeur) { double(id: 1) }
|
||||
let(:procedure) { double(id: 1) }
|
||||
let(:procedure_presentation) { double(instructeur:, procedure:) }
|
||||
let(:instance) { described_class.new(procedure_presentation:, statut: 'a-suivre') }
|
||||
|
||||
before do
|
||||
instance.save_context(ids: cached_ids, incoming_page: nil)
|
||||
end
|
||||
|
||||
describe 'next_dossier_id' do
|
||||
context 'when procedure.dossiers.by_statut has only one page' do
|
||||
let(:cached_ids) { [3, 4] }
|
||||
before do
|
||||
allow(instance).to receive(:fetch_all_ids).and_return(cached_ids)
|
||||
end
|
||||
|
||||
it 'find next until the end' do
|
||||
expect(instance.next_dossier_id(from_id: cached_ids.last)).to eq(nil)
|
||||
expect(instance.next_dossier_id(from_id: cached_ids.first)).to eq(cached_ids.last)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when procedure.dossiers.by_statut has more than one page' do
|
||||
let(:cached_ids) { [2, 3, 4] }
|
||||
let(:next_page_ids) { (0..10).to_a }
|
||||
|
||||
subject { instance.next_dossier_id(from_id: cached_ids.last) }
|
||||
before do
|
||||
allow(instance).to receive(:fetch_all_ids).and_return(next_page_ids)
|
||||
end
|
||||
|
||||
it 'refreshes paginated_ids' do
|
||||
expect { subject }.to change { instance.send(:ids) }.from(cached_ids).to(next_page_ids)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when procedure.dossiers.by_statut does not include searched dossiers anymore' do
|
||||
let(:cached_ids) { [] }
|
||||
let(:next_page_ids) { [] }
|
||||
before { allow(instance).to receive(:fetch_all_ids).and_return(next_page_ids) }
|
||||
|
||||
it 'works' do
|
||||
expect(instance.next_dossier_id(from_id: 50)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'previous_dossier_id' do
|
||||
context 'when procedure.dossiers.by_statut has only one page' do
|
||||
let(:cached_ids) { [3, 4] }
|
||||
before do
|
||||
allow(instance).to receive(:fetch_all_ids).and_return(cached_ids)
|
||||
end
|
||||
|
||||
it 'find next until the end' do
|
||||
expect(instance.previous_dossier_id(from_id: cached_ids.last)).to eq(cached_ids.first)
|
||||
expect(instance.previous_dossier_id(from_id: cached_ids.first)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when procedure.dossiers.by_statut has more than one page' do
|
||||
let(:cached_ids) { [11, 12, 13] }
|
||||
subject { instance.previous_dossier_id(from_id: cached_ids.first) }
|
||||
let(:next_page_ids) { (11..20).to_a }
|
||||
before do
|
||||
allow(instance).to receive(:fetch_all_ids).and_return(next_page_ids)
|
||||
end
|
||||
|
||||
it 'works' do
|
||||
expect { subject }.to change { instance.send(:ids) }.from(cached_ids).to(next_page_ids)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when procedure.dossiers.by_statut does not include searched dossiers anymore' do
|
||||
let(:cached_ids) { [] }
|
||||
before { allow(instance).to receive(:fetch_all_ids).and_return([]) }
|
||||
|
||||
it 'works' do
|
||||
expect(instance.previous_dossier_id(from_id: 50)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,12 +3,15 @@
|
|||
describe 'instructeurs/dossiers/annotations_privees', type: :view do
|
||||
let(:current_instructeur) { create(:instructeur) }
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
let(:procedure_presentation) { double(instructeur: current_instructeur, procedure: dossier.procedure) }
|
||||
|
||||
before do
|
||||
sign_in(current_instructeur.user)
|
||||
allow(view).to receive(:current_instructeur).and_return(current_instructeur)
|
||||
|
||||
allow(controller).to receive(:params).and_return({ statut: 'a-suivre' })
|
||||
assign(:dossier, dossier)
|
||||
assign(:procedure_presentation, procedure_presentation)
|
||||
end
|
||||
|
||||
subject { render }
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
describe 'instructeurs/dossiers/show', type: :view do
|
||||
let(:current_instructeur) { create(:instructeur) }
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
let(:statut) { { statut: 'tous' } }
|
||||
let(:procedure_presentation) { double(instructeur: current_instructeur, procedure: dossier.procedure) }
|
||||
|
||||
before do
|
||||
sign_in(current_instructeur.user)
|
||||
allow(view).to receive(:current_instructeur).and_return(current_instructeur)
|
||||
allow(controller).to receive(:params).and_return(statut: 'a-suivre')
|
||||
allow(controller).to receive(:params).and_return(statut:)
|
||||
assign(:dossier, dossier)
|
||||
assign(:procedure_presentation, procedure_presentation)
|
||||
end
|
||||
|
||||
subject { render }
|
||||
|
@ -17,6 +20,12 @@ describe 'instructeurs/dossiers/show', type: :view do
|
|||
expect(subject).to have_text("Dossier nº #{dossier.id}")
|
||||
end
|
||||
|
||||
context 'when procedure statut / page was saved in session' do
|
||||
it 'renders back button with saved state' do
|
||||
expect(subject).to have_selector("a[href=\"#{instructeur_procedure_path(dossier.procedure, statut: statut)}\"]")
|
||||
end
|
||||
end
|
||||
|
||||
it 'renders the dossier infos' do
|
||||
expect(subject).to have_text('Identité')
|
||||
expect(subject).to have_text('Demande')
|
||||
|
|
Loading…
Reference in a new issue