diff --git a/app/assets/stylesheets/all_demarches.scss b/app/assets/stylesheets/all_demarches.scss new file mode 100644 index 000000000..c15a743ba --- /dev/null +++ b/app/assets/stylesheets/all_demarches.scss @@ -0,0 +1,3 @@ +#all-demarches .procedure { + cursor: pointer; +} diff --git a/app/assets/stylesheets/sidebar_filter.scss b/app/assets/stylesheets/sidebar_filter.scss new file mode 100644 index 000000000..af76ae5fe --- /dev/null +++ b/app/assets/stylesheets/sidebar_filter.scss @@ -0,0 +1,14 @@ +.sidebar-filter { + ul { + list-style: none; + padding-inline-start: 0; + border-top: 1px solid var(--border-plain-grey); + } + li { + border-bottom: 1px solid var(--border-plain-grey); + } + button { + font-size: 1rem; + line-height: 1.5rem; + } +} diff --git a/app/controllers/administrateurs/procedures_controller.rb b/app/controllers/administrateurs/procedures_controller.rb index 16743c768..3dfbdfd6f 100644 --- a/app/controllers/administrateurs/procedures_controller.rb +++ b/app/controllers/administrateurs/procedures_controller.rb @@ -325,6 +325,16 @@ module Administrateurs @procedure = Procedure.includes(draft_revision: { revision_types_de_champ_public: :type_de_champ }).find(@procedure.id) end + def all + @admin_zones = current_administrateur.zones + @other_zones = Zone.all - @admin_zones + @zone_ids = params[:zone_ids].filter(&:present?) if params[:zone_ids] + @selected_zones = @zone_ids.map { |id| Zone.find(id) } if @zone_ids && @zone_ids.any? + + @procedures = Procedure.joins(:procedures_zones).publiees_ou_closes + @procedures = @procedures.where(procedures_zones: { zone_id: @zone_ids }) if @zone_ids && @zone_ids.any? + end + private def draft_valid? diff --git a/app/javascript/controllers/expand_controller.ts b/app/javascript/controllers/expand_controller.ts new file mode 100644 index 000000000..48352c08d --- /dev/null +++ b/app/javascript/controllers/expand_controller.ts @@ -0,0 +1,15 @@ +import { ApplicationController } from './application_controller'; +import { toggle, toggleExpandIcon } from '@utils'; + +export class ExpandController extends ApplicationController { + static targets = ['content', 'icon']; + + declare readonly contentTarget: HTMLElement; + declare readonly iconTarget: HTMLElement; + + toggle(event: Event) { + event.preventDefault(); + toggle(this.contentTarget); + toggleExpandIcon(this.iconTarget); + } +} diff --git a/app/javascript/shared/utils.test.ts b/app/javascript/shared/utils.test.ts index 4aaa569d5..3e22adcf4 100644 --- a/app/javascript/shared/utils.test.ts +++ b/app/javascript/shared/utils.test.ts @@ -4,6 +4,7 @@ import { show, hide, toggle, + toggleExpandIcon, isSelectElement, isTextInputElement, isCheckboxOrRadioInputElement @@ -34,6 +35,20 @@ suite('@utils', () => { expect(input.classList.contains('hidden')).toBeFalsy(); }); + test('toggleExpandIcon', () => { + const icon = document.createElement('icon'); + icon.classList.add('fr-icon-add-line'); + + toggleExpandIcon(icon); + console.log(icon.outerHTML); + expect(icon.classList.contains('fr-icon-subtract-line')).toBeTruthy(); + expect(icon.classList.contains('fr-icon-add-line')).toBeFalsy(); + toggleExpandIcon(icon); + expect(icon.classList.contains('fr-icon-add-line')).toBeTruthy(); + expect(icon.classList.contains('fr-icon-subtract-line')).toBeFalsy(); + console.log(icon.outerHTML); + }); + test('isSelectElement', () => { const select = document.createElement('select'); const input = document.createElement('input'); diff --git a/app/javascript/shared/utils.ts b/app/javascript/shared/utils.ts index 94c511065..f52c63011 100644 --- a/app/javascript/shared/utils.ts +++ b/app/javascript/shared/utils.ts @@ -83,6 +83,11 @@ export function toggle(el: Element | null, force?: boolean) { } } +export function toggleExpandIcon(icon: Element | null) { + icon?.classList.toggle('fr-icon-add-line'); + icon?.classList.toggle('fr-icon-subtract-line'); +} + export function enable( el: HTMLSelectElement | HTMLInputElement | HTMLButtonElement | null ) { diff --git a/app/models/zone.rb b/app/models/zone.rb index 5d34310da..e48eab1df 100644 --- a/app/models/zone.rb +++ b/app/models/zone.rb @@ -14,7 +14,7 @@ class Zone < ApplicationRecord has_and_belongs_to_many :procedures, -> { order(published_at: :desc) }, inverse_of: :zone def current_label - labels.first.name + labels.where.not(name: 'Non attribué').first.name end def label_at(date) diff --git a/app/views/administrateurs/procedures/all.html.haml b/app/views/administrateurs/procedures/all.html.haml new file mode 100644 index 000000000..aaa4b5010 --- /dev/null +++ b/app/views/administrateurs/procedures/all.html.haml @@ -0,0 +1,83 @@ +.fr-container + %h1.fr-my-4w Toutes les démarches + + .fr-container--fluid + .fr-grid-row.fr-grid-row--gutters + .fr-col-8 + .fr-highlight.fr-mb-4w + %p Ce tableau de bord permet de consulter les informations sur les démarches simplifiées pour toutes les zones. Filtrez par zone et statut. Consultez la liste des démarches et cliquez sur une démarche pour voir la zone et quels sont les administrateurs. + + + + .fr-container--fluid + .fr-grid-row.fr-grid-row--gutters + .fr-col-3 + = form_with url: all_admin_procedures_path, method: :get do |f| + + %fieldset.sidebar-filter + %legend.font-weight-bold.fr-pl-2w + %span.fr-icon-filter-fill.fr-icon--sm.fr-mr-1w{'aria-hidden': 'true'} + Filtrer + %ul + %li.fr-py-2w.fr-pl-2w{'data-controller': "expand"} + .fr-mb-1w{'data-action': 'click->expand#toggle'} + %button + %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, @admin_zones, :id, :current_label, include_hidden: false do |b| + .fr-checkbox-group.fr-ml-2w + = b.check_box(checked: @zone_ids&.map(&:to_i)&.include?(b.value)) + = b.label(class: 'fr-label') { b.text } + %li.fr-py-2w.fr-pl-2w{'data-controller': "expand"} + .fr-mb-1w{'data-action': 'click->expand#toggle'} + %button + %span.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-text-action-high--blue-france{'aria-hidden': 'true', 'data-expand-target': 'icon'} + Autres zones + .fr-ml-1w.hidden{'data-expand-target': 'content'} + = f.collection_check_boxes :zone_ids, @other_zones, :id, :current_label, include_hidden: false do |b| + .fr-checkbox-group.fr-ml-2w + = b.check_box(checked: @zone_ids&.map(&:to_i)&.include?(b.value)) + = b.label(class: 'fr-label') { b.text } + = f.submit 'Filtrer', class: 'fr-btn' + + .fr-col-9 + .fr-table.fr-table--bordered + %table#all-demarches + %caption= "#{@procedures.count} démarches" + - if @selected_zones + .selected-zones.fr-mb-2w + - @selected_zones.each do |zone| + %p.fr-tag.fr-mb-1w.fr--background-alt-blue-france= zone.current_label + %thead + %tr + %th{scope: 'col'} + %th{scope: 'col'} Démarche + %th{scope: 'col'} N° + %th{scope: 'col'} Administrateurs + %th{scope: 'col'} Statut + %th{scope: 'col'} Date + - @procedures.each do |procedure| + %tbody{'data-controller': 'expand'} + %tr.procedure{'data-action': 'click->expand#toggle'} + %td + %button.fr-icon-add-line.fr-icon--sm.fr-mr-1w.fr-mb-1w.fr-text-action-high--blue-france{'aria-hidden': 'true', 'data-expand-target': 'icon'} + %td= procedure.libelle + %td= procedure.id + %td= procedure.administrateurs.count + %td= procedure.aasm_state + %td= procedure.created_at + %tr.hidden{'data-expand-target': 'content'} + %td.fr-highlight--beige-gris-galet{colspan: '6'} + .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 + + + + diff --git a/config/routes.rb b/config/routes.rb index ed05b5cb7..a03dc0dfa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -428,6 +428,7 @@ Rails.application.routes.draw do collection do get 'new_from_existing' post 'search' + get 'all' end member do diff --git a/spec/controllers/administrateurs/procedures_controller_spec.rb b/spec/controllers/administrateurs/procedures_controller_spec.rb index 1fad0fcea..3692c49f7 100644 --- a/spec/controllers/administrateurs/procedures_controller_spec.rb +++ b/spec/controllers/administrateurs/procedures_controller_spec.rb @@ -87,6 +87,41 @@ describe Administrateurs::ProceduresController, type: :controller do it { expect(subject.status).to eq(200) } end + describe 'GET #all' do + let!(:draft_procedure) { create(:procedure) } + let!(:published_procedure) { create(:procedure_with_dossiers, :published, dossiers_count: 2) } + let!(:closed_procedure) { create(:procedure, :closed) } + subject { get :all } + + it { expect(subject.status).to eq(200) } + + it 'display published or closed procedures' do + subject + expect(assigns(:procedures)).to include(published_procedure) + expect(assigns(:procedures)).to include(closed_procedure) + end + + it 'doesn’t display draft procedures' do + subject + expect(assigns(:procedures)).not_to include(draft_procedure) + end + + context "for specific zones" do + let(:zone1) { create(:zone) } + let(:zone2) { create(:zone) } + let!(:procedure1) { create(:procedure, :published, zones: [zone1]) } + let!(:procedure2) { create(:procedure, :published, zones: [zone1, zone2]) } + + subject { get :all, params: { zone_ids: [zone2.id] } } + + it 'display only procedures for specified zones' do + subject + expect(assigns(:procedures)).to include(procedure2) + expect(assigns(:procedures)).not_to include(procedure1) + end + end + end + describe 'POST #search' do before do stub_const("Administrateurs::ProceduresController::SIGNIFICANT_DOSSIERS_THRESHOLD", 2)