Skip to content

Commit

Permalink
Merge pull request #10850 from demarches-simplifiees/add_id_to_column
Browse files Browse the repository at this point in the history
Tech: utilise des colonnes id dans les `ProcedurePresentation`
  • Loading branch information
LeSim authored Oct 8, 2024
2 parents 73eed5d + d5a722c commit c072ee7
Show file tree
Hide file tree
Showing 23 changed files with 342 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= form_tag update_sort_instructeur_procedure_path(procedure_id: @procedure.id, column_id: 'notifications/notifications', order: opposite_order), method: :get, data: { controller: 'autosubmit' } do
= form_tag update_sort_instructeur_procedure_path(procedure_id: @procedure.id, column_id: @procedure.notifications_column.id, order: opposite_order), method: :get, data: { controller: 'autosubmit' } do
.fr-fieldset__element.fr-m-0
.fr-checkbox-group.fr-checkbox-group--sm
= check_box_tag :order, opposite_order, active?
Expand Down
2 changes: 1 addition & 1 deletion app/components/instructeurs/column_picker_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def initialize(procedure:, procedure_presentation:)
def displayable_columns_for_select
[
procedure.columns.filter(&:displayable).map { |column| [column.label, column.id] },
procedure_presentation.displayed_fields.map { Column.new(**_1.deep_symbolize_keys).id }
procedure_presentation.displayed_fields.map { Column.new(**_1.deep_symbolize_keys.merge(procedure_id: procedure.id)).id }
]
end
end
2 changes: 1 addition & 1 deletion app/controllers/instructeurs/procedures_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def update_filter
@statut = statut
@procedure = procedure
@procedure_presentation = procedure_presentation
@column = procedure.find_column(id: params[:column])
@column = procedure.find_column(h_id: JSON.parse(params[:column], symbolize_names: true))
end

def remove_filter
Expand Down
18 changes: 5 additions & 13 deletions app/models/column.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ class Column

attr_reader :table, :column, :label, :classname, :type, :scope, :value_column, :filterable, :displayable

def initialize(table:, column:, label: nil, type: :text, value_column: :value, filterable: true, displayable: true, classname: '', scope: '')
def initialize(procedure_id:, table:, column:, label: nil, type: :text, value_column: :value, filterable: true, displayable: true, classname: '', scope: '')
@procedure_id = procedure_id
@table = table
@column = column
@label = label || I18n.t(column, scope: [:activerecord, :attributes, :procedure_presentation, :fields, table])
Expand All @@ -14,21 +15,12 @@ def initialize(table:, column:, label: nil, type: :text, value_column: :value, f
@scope = scope
@value_column = value_column
@filterable = filterable
# We need this for backward compatibility
@displayable = displayable
end

def id
"#{table}/#{column}"
end

def self.make_id(table, column)
"#{table}/#{column}"
end

def ==(other)
other.to_json == to_json
end
def id = h_id.to_json
def h_id = { procedure_id: @procedure_id, column_id: "#{table}/#{column}" }
def ==(other) = h_id == other.h_id # using h_id instead of id to avoid inversion of keys

def to_json
{
Expand Down
3 changes: 2 additions & 1 deletion app/models/concerns/addressable_column_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ module AddressableColumnConcern
extend ActiveSupport::Concern

included do
def columns(displayable: true, prefix: nil)
def columns(procedure_id:, displayable: true, prefix: nil)
super.concat([
["code postal (5 chiffres)", ['postal_code'], :text],
["commune", ['city_name'], :text],
["département", ['departement_code'], :enum],
["region", ['region_name'], :enum]
].map do |(label, value_column, type)|
Columns::JSONPathColumn.new(
procedure_id:,
table: Column::TYPE_DE_CHAMP_TABLE,
column: stable_id,
label: "#{libelle_with_prefix(prefix)}#{label}",
Expand Down
43 changes: 27 additions & 16 deletions app/models/concerns/columns_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ module ColumnsConcern
extend ActiveSupport::Concern

included do
def find_column(id:) = columns.find { |f| f.id == id }
def find_column(h_id: nil, label: nil)
return columns.find { _1.h_id == h_id } if h_id.present?
return columns.find { _1.label == label } if label.present?
end

def columns
columns = dossier_columns
Expand All @@ -14,16 +17,24 @@ def columns
columns.concat(types_de_champ_columns)
end

def dossier_id_column
Column.new(procedure_id: id, table: 'self', column: 'id', classname: 'number-col', type: :number)
end

def notifications_column
Column.new(procedure_id: id, table: 'notifications', column: 'notifications', label: "notifications", filterable: false)
end

def dossier_columns
common = [Column.new(table: 'self', column: 'id', classname: 'number-col', type: :number), Column.new(table: 'notifications', column: 'notifications', label: "notifications", filterable: false)]
common = [dossier_id_column, notifications_column]

dates = ['created_at', 'updated_at', 'depose_at', 'en_construction_at', 'en_instruction_at', 'processed_at']
.map { |column| Column.new(table: 'self', column:, type: :date) }
.map { |column| Column.new(procedure_id: id, table: 'self', column:, type: :date) }

non_displayable_dates = ['updated_since', 'depose_since', 'en_construction_since', 'en_instruction_since', 'processed_since']
.map { |column| Column.new(table: 'self', column:, type: :date, displayable: false) }
.map { |column| Column.new(procedure_id: id, table: 'self', column:, type: :date, displayable: false) }

states = [Column.new(table: 'self', column: 'state', type: :enum, scope: 'instructeurs.dossiers.filterable_state', displayable: false)]
states = [Column.new(procedure_id: id, table: 'self', column: 'state', type: :enum, scope: 'instructeurs.dossiers.filterable_state', displayable: false)]

[common, dates, sva_svr_columns(for_filters: true), non_displayable_dates, states].flatten.compact
end
Expand All @@ -34,12 +45,12 @@ def sva_svr_columns(for_filters: false)
scope = [:activerecord, :attributes, :procedure_presentation, :fields, :self]

columns = [
Column.new(table: 'self', column: 'sva_svr_decision_on', type: :date,
Column.new(procedure_id: id, table: 'self', column: 'sva_svr_decision_on', type: :date,
label: I18n.t("#{sva_svr_decision}_decision_on", scope:), classname: for_filters ? '' : 'sva-col')
]

if for_filters
columns << Column.new(table: 'self', column: 'sva_svr_decision_before', type: :date, displayable: false,
columns << Column.new(procedure_id: id, table: 'self', column: 'sva_svr_decision_before', type: :date, displayable: false,
label: I18n.t("#{sva_svr_decision}_decision_before", scope:))
end

Expand All @@ -50,30 +61,30 @@ def sva_svr_columns(for_filters: false)

def standard_columns
[
Column.new(table: 'user', column: 'email'),
Column.new(table: 'followers_instructeurs', column: 'email'),
Column.new(table: 'groupe_instructeur', column: 'id', type: :enum),
Column.new(table: 'avis', column: 'question_answer', filterable: false) # not filterable ?
Column.new(procedure_id: id, table: 'user', column: 'email'),
Column.new(procedure_id: id, table: 'followers_instructeurs', column: 'email'),
Column.new(procedure_id: id, table: 'groupe_instructeur', column: 'id', type: :enum),
Column.new(procedure_id: id, table: 'avis', column: 'question_answer', filterable: false) # not filterable ?
]
end

def individual_columns
['nom', 'prenom', 'gender'].map { |column| Column.new(table: 'individual', column:) }
['nom', 'prenom', 'gender'].map { |column| Column.new(procedure_id: id, table: 'individual', column:) }
end

def moral_columns
etablissements = ['entreprise_siren', 'entreprise_forme_juridique', 'entreprise_nom_commercial', 'entreprise_raison_sociale', 'entreprise_siret_siege_social']
.map { |column| Column.new(table: 'etablissement', column:) }
.map { |column| Column.new(procedure_id: id, table: 'etablissement', column:) }

etablissement_dates = ['entreprise_date_creation'].map { |column| Column.new(table: 'etablissement', column:, type: :date) }
etablissement_dates = ['entreprise_date_creation'].map { |column| Column.new(procedure_id: id, table: 'etablissement', column:, type: :date) }

other = ['siret', 'libelle_naf', 'code_postal'].map { |column| Column.new(table: 'etablissement', column:) }
other = ['siret', 'libelle_naf', 'code_postal'].map { |column| Column.new(procedure_id: id, table: 'etablissement', column:) }

[etablissements, etablissement_dates, other].flatten
end

def types_de_champ_columns
all_revisions_types_de_champ.flat_map(&:columns)
all_revisions_types_de_champ.flat_map { _1.columns(procedure_id: id) }
end
end
end
8 changes: 0 additions & 8 deletions app/models/procedure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -613,14 +613,6 @@ def email_template_for(state)
end
end

def self.default_sort
{
'table' => 'self',
'column' => 'id',
'order' => 'desc'
}
end

def whitelist!
touch(:whitelisted_at)
end
Expand Down
68 changes: 52 additions & 16 deletions app/models/procedure_presentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,28 @@ class ProcedurePresentation < ApplicationRecord
validate :check_filters_max_length
validate :check_filters_max_integer

attribute :sorted_column, :jsonb

attribute :a_suivre_filters, :jsonb, array: true
attribute :suivis_filters, :jsonb, array: true
attribute :traites_filters, :jsonb, array: true
attribute :tous_filters, :jsonb, array: true
attribute :supprimes_filters, :jsonb, array: true
attribute :supprimes_recemment_filters, :jsonb, array: true
attribute :expirant_filters, :jsonb, array: true
attribute :archives_filters, :jsonb, array: true

def filters_for(statut)
send(filters_name_for(statut))
end

def filters_name_for(statut) = statut.tr('-', '_').then { "#{_1}_filters" }

def displayed_fields_for_headers
[
Column.new(table: 'self', column: 'id', classname: 'number-col'),
*displayed_fields.map { Column.new(**_1.deep_symbolize_keys) },
Column.new(table: 'self', column: 'state', classname: 'state-col'),
Column.new(procedure_id: procedure.id, table: 'self', column: 'id', classname: 'number-col'),
*displayed_fields.map { Column.new(**_1.deep_symbolize_keys.merge(procedure_id: procedure.id)) },
Column.new(procedure_id: procedure.id, table: 'self', column: 'state', classname: 'state-col'),
*procedure.sva_svr_columns
]
end
Expand Down Expand Up @@ -81,8 +98,10 @@ def safe_parse_date(string)
end

def add_filter(statut, column_id, value)
h_id = JSON.parse(column_id, symbolize_names: true)

if value.present?
column = procedure.find_column(id: column_id)
column = procedure.find_column(h_id:)

case column.table
when TYPE_DE_CHAMP
Expand All @@ -98,40 +117,57 @@ def add_filter(statut, column_id, value)
'value' => value
}

filters_for(statut) << { id: h_id, filter: value }
update(filters: updated_filters)
end
end

def remove_filter(statut, column_id, value)
column = procedure.find_column(id: column_id)
h_id = JSON.parse(column_id, symbolize_names: true)
column = procedure.find_column(h_id:)
updated_filters = filters.dup

updated_filters[statut] = filters[statut].reject do |filter|
filter.values_at(TABLE, COLUMN, 'value') == [column.table, column.column, value]
end

collection = filters_for(statut)
collection.delete(collection.find { sym_h = _1.deep_symbolize_keys; sym_h[:id] == h_id && sym_h[:filter] == value })

update!(filters: updated_filters)
end

def update_displayed_fields(column_ids)
column_ids = Array.wrap(column_ids)
columns = column_ids.map { |id| procedure.find_column(id:) }
h_ids = Array.wrap(column_ids).map { |id| JSON.parse(id, symbolize_names: true) }
columns = h_ids.map { |h_id| procedure.find_column(h_id:) }

update!(displayed_fields: columns)
update!(
displayed_fields: columns,
displayed_columns: columns.map(&:h_id)
)

if !sort_to_column_id(sort).in?(column_ids)
update!(sort: Procedure.default_sort)
default_column_id = procedure.dossier_id_column.id
update_sort(default_column_id, "desc")
end
end

def update_sort(column_id, order)
column = procedure.find_column(id: column_id)
h_id = JSON.parse(column_id, symbolize_names: true)
column = procedure.find_column(h_id:)
order = order.presence || opposite_order_for(column.table, column.column)

update!(sort: {
TABLE => column.table,
COLUMN => column.column,
ORDER => order.presence || opposite_order_for(column.table, column.column)
})
update!(
sort: {
TABLE => column.table,
COLUMN => column.column,
ORDER => order
},
sorted_column: {
order:,
id: h_id
}
)
end

def opposite_order_for(table, column)
Expand Down Expand Up @@ -201,7 +237,7 @@ def filtered_ids(dossiers, statut)
.map do |(table, column), filters|
values = filters.pluck('value')
value_column = filters.pluck('value_column').compact.first || :value
dossier_column = procedure.find_column(id: Column.make_id(table, column)) # hack to find json path columns
dossier_column = procedure.find_column(h_id: { procedure_id: procedure.id, column_id: "#{table}/#{column}" }) # hack to find json path columns
if dossier_column.is_a?(Columns::JSONPathColumn)
dossier_column.filtered_ids(dossiers, values)
else
Expand Down
4 changes: 2 additions & 2 deletions app/models/types_de_champ/repetition_type_de_champ.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ def libelle_for_export
ActiveStorage::Filename.new(str.delete('[]*?')).sanitized
end

def columns(displayable: true, prefix: nil)
def columns(procedure_id:, displayable: true, prefix: nil)
@type_de_champ.procedure
.all_revisions_types_de_champ(parent: @type_de_champ)
.flat_map { _1.columns(displayable: false, prefix: libelle) }
.flat_map { _1.columns(procedure_id:, displayable: false, prefix: libelle) }
end
end
3 changes: 2 additions & 1 deletion app/models/types_de_champ/type_de_champ_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ def champ_default_api_value(version = 2)
end
end

def columns(displayable: true, prefix: nil)
def columns(procedure_id:, displayable: true, prefix: nil)
[
Column.new(
procedure_id:,
table: Column::TYPE_DE_CHAMP_TABLE,
column: stable_id.to_s,
label: libelle_with_prefix(prefix),
Expand Down
8 changes: 4 additions & 4 deletions app/models/types_de_champ/yes_no_type_de_champ.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ def filter_to_human(filter_value)
end

def human_to_filter(human_value)
human_value.downcase!
if human_value == "oui"
downcased = human_value.downcase
if downcased == "oui"
"true"
elsif human_value == "non"
elsif downcased == "non"
"false"
else
human_value
downcased
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
- filters.each_with_index do |filter, i|
- if i > 0
= " ou "
= link_to remove_filter_instructeur_procedure_path(procedure, { statut: statut, column: "#{filter['table']}/#{filter['column']}", value: filter['value'] }),
= link_to remove_filter_instructeur_procedure_path(procedure, { statut: statut, column: { procedure_id: procedure.id, column_id: filter['table'] + "/" + filter['column'] }.to_json, value: filter['value'] }),
class: "fr-tag fr-tag--dismiss fr-my-1w", aria: { label: "Retirer le filtre #{filter['column']}" } do
= "#{filter['label'].truncate(50)} : #{procedure_presentation.human_value_for_filter(filter)}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class AddColumnIdsToProcedurePresentations < ActiveRecord::Migration[7.0]
def change
add_column :procedure_presentations, :displayed_columns, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :tous_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :suivis_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :traites_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :a_suivre_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :archives_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :expirant_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :supprimes_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :supprimes_recemment_filters, :jsonb, array: true, default: [], null: false
add_column :procedure_presentations, :sorted_column, :jsonb
end
end
10 changes: 10 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -866,11 +866,21 @@
end

create_table "procedure_presentations", id: :serial, force: :cascade do |t|
t.jsonb "a_suivre_filters", default: [], null: false, array: true
t.jsonb "archives_filters", default: [], null: false, array: true
t.integer "assign_to_id"
t.datetime "created_at", precision: nil
t.jsonb "displayed_columns", default: [], null: false, array: true
t.jsonb "displayed_fields", default: [{"label"=>"Demandeur", "table"=>"user", "column"=>"email"}], null: false
t.jsonb "expirant_filters", default: [], null: false, array: true
t.jsonb "filters", default: {"tous"=>[], "suivis"=>[], "traites"=>[], "a-suivre"=>[], "archives"=>[], "expirant"=>[], "supprimes"=>[]}, null: false
t.jsonb "sort", default: {"order"=>"desc", "table"=>"notifications", "column"=>"notifications"}, null: false
t.jsonb "sorted_column"
t.jsonb "suivis_filters", default: [], null: false, array: true
t.jsonb "supprimes_filters", default: [], null: false, array: true
t.jsonb "supprimes_recemment_filters", default: [], null: false, array: true
t.jsonb "tous_filters", default: [], null: false, array: true
t.jsonb "traites_filters", default: [], null: false, array: true
t.datetime "updated_at", precision: nil
t.index ["assign_to_id"], name: "index_procedure_presentations_on_assign_to_id", unique: true
end
Expand Down
Loading

0 comments on commit c072ee7

Please sign in to comment.