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:
commit
2371705efc
7 changed files with 75 additions and 47 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
- procedure.zones.uniq.each do |zone|
|
|
||||||
= zone.label_at(procedure.published_or_created_at)
|
|
||||||
.fr-col-6
|
.fr-col-6
|
||||||
- procedure.administrateurs.uniq.each do |admin|
|
- procedure.administrateurs.uniq.each do |admin|
|
||||||
= admin.email
|
= admin.email
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
= b.check_box(checked: @filter.zone_filtered?(b.value))
|
= f.check_box :template, class: 'fr-input'
|
||||||
= b.label(class: 'fr-label') { b.text }
|
= f.label :template, 'Modèle DS', class: 'fr-label'
|
||||||
%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)
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
Loading…
Reference in a new issue