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_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)
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
def spreadsheet_columns
@ -12,4 +12,11 @@ ProcedureDetail = Struct.new(:id, :libelle, :published_at, :aasm_state, :estimat
def administrateurs
AdministrateursCounter.new(admin_count)
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

View file

@ -5,15 +5,23 @@
- 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
= title
%td
- if procedure.template
%p.fr-badge.fr-badge--info.fr-badge--sm= "Modèle DS"
%br
%p.fr-badge.fr-badge--info.fr-badge--sm= "Modèle"
%abbr{ title: APPLICATION_NAME }= acronymize(APPLICATION_NAME)
= procedure.libelle
%td= procedure.id
%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= l(procedure.published_at, format: :message_date_without_time) if procedure.published_at
%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')
- if show_detail
%tr.procedure{ id: "procedure_detail_#{procedure.id}" }
%td.fr-highlight--beige-gris-galet{ colspan: '8' }
.fr-container
.fr-grid-row
.fr-col-6
- procedure.zones.uniq.each do |zone|
= 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") }
.fr-fieldset__element
= f.label :tags, 'Associez les tags à 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.
= f.label :tags, 'Associez des thématiques à la démarche', class: 'fr-label'
%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)
= react_component("ComboMultiple",
id: "procedure_tags_combo",

View file

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

View file

@ -1,6 +1,5 @@
- content_for(:main_navigation) do
= render 'administrateurs/main_navigation'
- content_for :content do
.fr-container
%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
%span.fr-icon-arrow-go-back-line Réinitialiser
%ul
%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{ 'data-expand-target': 'content' }
= f.collection_check_boxes :zone_ids, @filter.admin_zones, :id, :current_label, include_hidden: false do |b|
Démarches modèles
.fr-ml-1w.hidden{ 'data-expand-target': 'content' }
.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 }
= f.check_box :template, class: 'fr-input'
= f.label :template, 'Modèle DS', class: 'fr-label'
%li.fr-py-2w.fr-pl-2w{ 'data-controller': "expand" }
.fr-mb-1w
%button{ 'data-action': 'expand#toggle' }
@ -45,6 +44,16 @@
.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" }
.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" }
.fr-mb-1w
%button{ 'data-action': 'expand#toggle' }
@ -65,6 +74,16 @@
{ selected: @filter.service_departement, include_blank: ''},
id: "service_dep_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" }
.fr-mb-1w.fr-pl-2w
%button{ 'data-action': 'click->expand#toggle' }
@ -86,39 +105,21 @@
= b.check_box(checked: @filter.status_filtered?(b.value))
= b.label(class: 'fr-label') { t b.text, scope: 'activerecord.attributes.procedure.aasm_state' }
%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.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
Thématique
.fr-ml-1w.hidden{ 'data-expand-target': 'content' }
%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
- Procedure.tags.each do |tag|
%option{ value: tag }
- if @filter.tags.present?
- @filter.tags.each do |tag|
= 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
= yield(:results)

View file

@ -91,6 +91,10 @@ describe Administrateurs::ProceduresController, type: :controller do
let!(:draft_procedure) { create(:procedure) }
let!(:published_procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2) }
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 }
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
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
let(:zone1) { create(:zone) }
let(:zone2) { create(:zone) }