Merge pull request #10437 from demarches-simplifiees/feat/10332

Amélioration de la page toutes les démarches :  Quick Wins
This commit is contained in:
Kara Diaby 2024-05-29 13:50:04 +00:00 committed by GitHub
commit 2371705efc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 75 additions and 47 deletions

View file

@ -482,7 +482,8 @@ module Administrateurs
procedures_result = procedures_result.where('unaccent(libelle) ILIKE unaccent(?)', "%#{filter.libelle}%") if filter.libelle.present? procedures_result = procedures_result.where('unaccent(libelle) ILIKE unaccent(?)', "%#{filter.libelle}%") if filter.libelle.present?
procedures_sql = procedures_result.to_sql procedures_sql = procedures_result.to_sql
sql = "select id, libelle, published_at, aasm_state, estimated_dossiers_count, template, count(administrateurs_procedures.administrateur_id) as admin_count from administrateurs_procedures inner join procedures on procedures.id = administrateurs_procedures.procedure_id where procedures.id in (#{procedures_sql}) group by procedures.id order by published_at desc" sql = "select procedures.id, libelle, published_at, aasm_state, estimated_dossiers_count, template, array_agg(distinct latest_labels.name) filter (where latest_labels.name is not null) as latest_zone_labels from administrateurs_procedures inner join procedures on procedures.id = administrateurs_procedures.procedure_id left join procedures_zones ON procedures.id = procedures_zones.procedure_id left join zones ON zones.id = procedures_zones.zone_id left join (select zone_id, name from zone_labels where (zone_id, designated_on) in (select zone_id, max(designated_on) from zone_labels group by zone_id)) as latest_labels on zones.id = latest_labels.zone_id
where procedures.id in (#{procedures_sql}) group by procedures.id order by published_at desc"
ActiveRecord::Base.connection.execute(sql) ActiveRecord::Base.connection.execute(sql)
end end

View file

@ -1,4 +1,4 @@
ProcedureDetail = Struct.new(:id, :libelle, :published_at, :aasm_state, :estimated_dossiers_count, :admin_count, :template, keyword_init: true) do ProcedureDetail = Struct.new(:id, :libelle, :published_at, :aasm_state, :estimated_dossiers_count, :admin_count, :template, :latest_zone_labels, keyword_init: true) do
include SpreadsheetArchitect include SpreadsheetArchitect
def spreadsheet_columns def spreadsheet_columns
@ -12,4 +12,11 @@ ProcedureDetail = Struct.new(:id, :libelle, :published_at, :aasm_state, :estimat
def administrateurs def administrateurs
AdministrateursCounter.new(admin_count) AdministrateursCounter.new(admin_count)
end end
def parsed_latest_zone_labels
# Replace curly braces with square brackets to make it a valid JSON array
JSON.parse(latest_zone_labels.tr('{', '[').tr('}', ']'))
rescue JSON::ParserError
[]
end
end end

View file

@ -5,15 +5,23 @@
- params = show_detail ? {} : { show_detail: true } - params = show_detail ? {} : { show_detail: true }
= button_to detail_admin_procedure_path(procedure["id"]), method: :post, params:, title:, class: [icon, "fr-icon--sm fr-mr-1w fr-mb-1w fr-text-action-high--blue-france fr-btn fr-btn--tertiary-no-outline" ] do = button_to detail_admin_procedure_path(procedure["id"]), method: :post, params:, title:, class: [icon, "fr-icon--sm fr-mr-1w fr-mb-1w fr-text-action-high--blue-france fr-btn fr-btn--tertiary-no-outline" ] do
= title = title
%td %td
- if procedure.template - if procedure.template
%p.fr-badge.fr-badge--info.fr-badge--sm= "Modèle DS" %p.fr-badge.fr-badge--info.fr-badge--sm= "Modèle"
%br %abbr{ title: APPLICATION_NAME }= acronymize(APPLICATION_NAME)
= procedure.libelle = procedure.libelle
%td= procedure.id %td= procedure.id
%td= procedure.estimated_dossiers_count %td= procedure.estimated_dossiers_count
%td= procedure.administrateurs.count %td
- if procedure.respond_to?(:parsed_latest_zone_labels)
- procedure.parsed_latest_zone_labels.uniq.each do |zone_label|
%span.mb-2= zone_label
.mb-2
- else
- procedure.zones.uniq.each do |zone|
%span= zone.current_label
.mb-1
%td= t procedure.aasm_state, scope: 'activerecord.attributes.procedure.aasm_state' %td= t procedure.aasm_state, scope: 'activerecord.attributes.procedure.aasm_state'
%td= l(procedure.published_at, format: :message_date_without_time) if procedure.published_at %td= l(procedure.published_at, format: :message_date_without_time) if procedure.published_at
%td %td
@ -21,16 +29,10 @@
= link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'fr-btn fr-btn--tertiary fr-btn--sm') = link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'fr-btn fr-btn--tertiary fr-btn--sm')
- if show_detail - if show_detail
%tr.procedure{ id: "procedure_detail_#{procedure.id}" } %tr.procedure{ id: "procedure_detail_#{procedure.id}" }
%td.fr-highlight--beige-gris-galet{ colspan: '8' } %td.fr-highlight--beige-gris-galet{ colspan: '8' }
.fr-container .fr-container
.fr-grid-row .fr-col-6
.fr-col-6 - procedure.administrateurs.uniq.each do |admin|
- procedure.zones.uniq.each do |zone| = admin.email
= zone.label_at(procedure.published_or_created_at)
.fr-col-6
- procedure.administrateurs.uniq.each do |admin|
= admin.email

View file

@ -120,8 +120,8 @@
%use.fr-artwork-major{ href: image_path("pictograms/buildings/school.svg#artwork-major") } %use.fr-artwork-major{ href: image_path("pictograms/buildings/school.svg#artwork-major") }
.fr-fieldset__element .fr-fieldset__element
= f.label :tags, 'Associez les tags à la démarche', class: 'fr-label' = f.label :tags, 'Associez des thématiques à la démarche', class: 'fr-label'
%p.fr-hint-text Les tags sont des mots ou des expressions que vous attribuez aux démarches pour décrire leur contenu et pour les retrouver. Les tags sont partagés avec la communauté, ce qui vous permet de voir les tags attribués aux démarches créées par les autres administrateurs. %p.fr-hint-text Par des mots ou des expressions que vous attribuez aux démarches pour décrire leur contenu et pour les retrouver. Les tags sont partagés avec la communauté, ce qui vous permet de voir les tags attribués aux démarches créées par les autres administrateurs.
= hidden_field_tag 'procedure[tags]', JSON.generate(@procedure.tags) = hidden_field_tag 'procedure[tags]', JSON.generate(@procedure.tags)
= react_component("ComboMultiple", = react_component("ComboMultiple",
id: "procedure_tags_combo", id: "procedure_tags_combo",

View file

@ -57,8 +57,8 @@
%th{ scope: 'col' } %th{ scope: 'col' }
%th{ scope: 'col' } Démarche %th{ scope: 'col' } Démarche
%th{ scope: 'col' } № %th{ scope: 'col' } №
%th{ scope: 'col' } Dossiers %th{ scope: 'col' } Nombre de dossiers
%th{ scope: 'col' } Administrateurs %th{ scope: 'col' } Zones
%th{ scope: 'col' } Statut %th{ scope: 'col' } Statut
%th{ scope: 'col' } Date %th{ scope: 'col' } Date
%th{ scope: 'col' } Action %th{ scope: 'col' } Action

View file

@ -1,6 +1,5 @@
- content_for(:main_navigation) do - content_for(:main_navigation) do
= render 'administrateurs/main_navigation' = render 'administrateurs/main_navigation'
- content_for :content do - content_for :content do
.fr-container .fr-container
%h1.fr-my-4w Toutes les démarches %h1.fr-my-4w Toutes les démarches
@ -25,16 +24,16 @@
= link_to all_admin_procedures_path(zone_ids: current_administrateur.zones), { data: { turbo: 'false' } } do = link_to all_admin_procedures_path(zone_ids: current_administrateur.zones), { data: { turbo: 'false' } } do
%span.fr-icon-arrow-go-back-line Réinitialiser %span.fr-icon-arrow-go-back-line Réinitialiser
%ul %ul
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" } %li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w .fr-mb-1w
%button{ 'data-action': 'expand#toggle' } %button{ 'data-action': 'expand#toggle' }
%span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' } %span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' }
Mes zones Démarches modèles
.fr-ml-1w{ 'data-expand-target': 'content' } .fr-ml-1w.hidden{ 'data-expand-target': 'content' }
= f.collection_check_boxes :zone_ids, @filter.admin_zones, :id, :current_label, include_hidden: false do |b| .fr-checkbox-group.fr-ml-2w.fr-py-1w
.fr-checkbox-group.fr-ml-2w.fr-py-1w = f.check_box :template, class: 'fr-input'
= b.check_box(checked: @filter.zone_filtered?(b.value)) = f.label :template, 'Modèle DS', class: 'fr-label'
= b.label(class: 'fr-label') { b.text }
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" } %li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w .fr-mb-1w
%button{ 'data-action': 'expand#toggle' } %button{ 'data-action': 'expand#toggle' }
@ -45,6 +44,16 @@
.fr-checkbox-group.fr-ml-2w.fr-py-1w .fr-checkbox-group.fr-ml-2w.fr-py-1w
= b.check_box(checked: @filter.zone_filtered?(b.value)) = b.check_box(checked: @filter.zone_filtered?(b.value))
= b.label(class: 'fr-label') { b.text } = b.label(class: 'fr-label') { b.text }
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w
%button{ 'data-action': 'expand#toggle' }
%span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' }
Mes zones
.fr-ml-1w.hidden{ 'data-expand-target': 'content' }
= f.collection_check_boxes :zone_ids, @filter.admin_zones, :id, :current_label, include_hidden: false do |b|
.fr-checkbox-group.fr-ml-2w.fr-py-1w
= b.check_box(checked: @filter.zone_filtered?(b.value))
= b.label(class: 'fr-label') { b.text }
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" } %li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w .fr-mb-1w
%button{ 'data-action': 'expand#toggle' } %button{ 'data-action': 'expand#toggle' }
@ -65,6 +74,16 @@
{ selected: @filter.service_departement, include_blank: ''}, { selected: @filter.service_departement, include_blank: ''},
id: "service_dep_select", id: "service_dep_select",
class: 'fr-select' class: 'fr-select'
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w
%button{ 'data-action': 'expand#toggle' }
%span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' }
Type d'usager
.fr-ml-1w.hidden{ 'data-expand-target': 'content' }
= f.collection_check_boxes :kind_usagers, ['individual', 'personne_morale'], :to_s, :to_s, include_hidden: false do |b|
.fr-checkbox-group.fr-ml-2w.fr-py-1w
= b.check_box(checked: @filter.kind_usager_filtered?(b.value))
= b.label(class: 'fr-label') { t b.text, scope: 'activerecord.attributes.procedure.kind_usager' }
%li.fr-py-2w{ 'data-controller': "expand" } %li.fr-py-2w{ 'data-controller': "expand" }
.fr-mb-1w.fr-pl-2w .fr-mb-1w.fr-pl-2w
%button{ 'data-action': 'click->expand#toggle' } %button{ 'data-action': 'click->expand#toggle' }
@ -86,39 +105,21 @@
= b.check_box(checked: @filter.status_filtered?(b.value)) = b.check_box(checked: @filter.status_filtered?(b.value))
= b.label(class: 'fr-label') { t b.text, scope: 'activerecord.attributes.procedure.aasm_state' } = b.label(class: 'fr-label') { t b.text, scope: 'activerecord.attributes.procedure.aasm_state' }
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" } %li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w .fr-mb-1w
%button{ 'data-action': 'expand#toggle' } %button{ 'data-action': 'expand#toggle' }
%span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' } %span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' }
Type d'usager Thématique
.fr-ml-1w.hidden{ 'data-expand-target': 'content' }
= f.collection_check_boxes :kind_usagers, ['individual', 'personne_morale'], :to_s, :to_s, include_hidden: false do |b|
.fr-checkbox-group.fr-ml-2w.fr-py-1w
= b.check_box(checked: @filter.kind_usager_filtered?(b.value))
= b.label(class: 'fr-label') { t b.text, scope: 'activerecord.attributes.procedure.kind_usager' }
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w
%button{ 'data-action': 'expand#toggle' }
%span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' }
Tags
.fr-ml-1w.hidden{ 'data-expand-target': 'content' } .fr-ml-1w.hidden{ 'data-expand-target': 'content' }
%div %div
= f.search_field :tags, placeholder: 'Choisissez un tag', list: 'tags_list', class: 'fr-input', data: { no_autosubmit: 'input', turbo_force: :server }, multiple: true = f.search_field :tags, placeholder: 'Choisissez un thème', list: 'tags_list', class: 'fr-input', data: { no_autosubmit: 'input', turbo_force: :server }, multiple: true
%datalist#tags_list %datalist#tags_list
- Procedure.tags.each do |tag| - Procedure.tags.each do |tag|
%option{ value: tag } %option{ value: tag }
- if @filter.tags.present? - if @filter.tags.present?
- @filter.tags.each do |tag| - @filter.tags.each do |tag|
= f.hidden_field :tags, value: tag, multiple: true, id: "tag-#{tag.tr(' ', '_')}" = f.hidden_field :tags, value: tag, multiple: true, id: "tag-#{tag.tr(' ', '_')}"
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w
%button{ 'data-action': 'expand#toggle' }
%span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{ 'aria-hidden': 'true', 'data-expand-target': 'icon' }
Démarches modèles
.fr-ml-1w.hidden{ 'data-expand-target': 'content' }
.fr-checkbox-group.fr-ml-2w.fr-py-1w
= f.check_box :template, class: 'fr-input'
= f.label :template, 'Modèle DS', class: 'fr-label'
.fr-col-9 .fr-col-9
= yield(:results) = yield(:results)

View file

@ -91,6 +91,10 @@ describe Administrateurs::ProceduresController, type: :controller do
let!(:draft_procedure) { create(:procedure) } let!(:draft_procedure) { create(:procedure) }
let!(:published_procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2) } let!(:published_procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2) }
let!(:closed_procedure) { create(:procedure, :closed) } let!(:closed_procedure) { create(:procedure, :closed) }
let!(:procedure_detail_draft) { ProcedureDetail.new(id: draft_procedure.id, latest_zone_labels: '{ "zone1", "zone2" }') }
let!(:procedure_detail_published) { ProcedureDetail.new(id: published_procedure.id, latest_zone_labels: '{ "zone3", "zone4" }') }
let!(:procedure_detail_closed) { ProcedureDetail.new(id: closed_procedure.id, latest_zone_labels: '{ "zone5", "zone6" }') }
subject { get :all } subject { get :all }
it { expect(subject.status).to eq(200) } it { expect(subject.status).to eq(200) }
@ -116,6 +120,19 @@ describe Administrateurs::ProceduresController, type: :controller do
expect(assigns(:procedures).any? { |p| p.id == draft_procedure.id }).to be_falsey expect(assigns(:procedures).any? { |p| p.id == draft_procedure.id }).to be_falsey
end end
context 'with parsed latest zone labels' do
it 'parses the latest zone labels correctly' do
expect(procedure_detail_draft.parsed_latest_zone_labels).to eq(["zone1", "zone2"])
expect(procedure_detail_published.parsed_latest_zone_labels).to eq(["zone3", "zone4"])
expect(procedure_detail_closed.parsed_latest_zone_labels).to eq(["zone5", "zone6"])
end
it 'returns an empty array for invalid JSON' do
procedure_detail_draft.latest_zone_labels = '{ invalid json }'
expect(procedure_detail_draft.parsed_latest_zone_labels).to eq([])
end
end
context 'for default admin zones' do context 'for default admin zones' do
let(:zone1) { create(:zone) } let(:zone1) { create(:zone) }
let(:zone2) { create(:zone) } let(:zone2) { create(:zone) }