types_de_champ controller to use turbo

This commit is contained in:
Paul Chavard 2022-06-01 15:23:18 +02:00 committed by Paul Chavard
parent cf81e8ecd5
commit 1573d20ee9
12 changed files with 133 additions and 58 deletions

View file

@ -1,16 +1,17 @@
module Administrateurs
class TypesDeChampController < AdministrateurController
before_action :retrieve_procedure, only: [:create, :update, :move, :estimate_fill_duration, :destroy]
before_action :procedure_revisable?, only: [:create, :update, :move, :destroy]
before_action :retrieve_procedure, only: [:create, :update, :move, :move_up, :move_down, :destroy]
before_action :procedure_revisable?, only: [:create, :update, :move, :move_up, :move_down, :destroy]
def create
type_de_champ = @procedure.draft_revision.add_type_de_champ(type_de_champ_create_params)
if type_de_champ.valid?
@coordinate = @procedure.draft_revision.coordinate_for(type_de_champ)
reset_procedure
render json: serialize_type_de_champ(type_de_champ), status: :created
flash.notice = "Formulaire enregistré"
else
render json: { errors: type_de_champ.errors.full_messages }, status: :unprocessable_entity
flash.alert = type_de_champ.errors.full_messages
end
end
@ -18,61 +19,43 @@ module Administrateurs
type_de_champ = @procedure.draft_revision.find_and_ensure_exclusive_use(params[:id])
if type_de_champ.update(type_de_champ_update_params)
if params[:should_render]
@coordinate = @procedure.draft_revision.coordinate_for(type_de_champ)
end
reset_procedure
render json: serialize_type_de_champ(type_de_champ)
flash.notice = "Formulaire enregistré"
else
render json: { errors: type_de_champ.errors.full_messages }, status: :unprocessable_entity
flash.alert = type_de_champ.errors.full_messages
end
end
def move
flash.notice = "Formulaire enregistré"
@procedure.draft_revision.move_type_de_champ(params[:id], params[:position].to_i)
head :no_content
end
def estimate_fill_duration
estimate = @procedure.draft_revision.estimated_fill_duration
render json: { estimated_fill_duration: estimate }
def move_up
flash.notice = "Formulaire enregistré"
@coordinate = @procedure.draft_revision.move_up_type_de_champ(params[:id])
end
def move_down
flash.notice = "Formulaire enregistré"
@coordinate = @procedure.draft_revision.move_down_type_de_champ(params[:id])
end
def destroy
@procedure.draft_revision.remove_type_de_champ(params[:id])
@coordinate = @procedure.draft_revision.remove_type_de_champ(params[:id])
reset_procedure
head :no_content
flash.notice = "Formulaire enregistré"
end
private
def serialize_type_de_champ(type_de_champ)
{ type_de_champ: type_de_champ.as_json_for_editor }
end
def type_de_champ_create_params
params.required(:type_de_champ).permit(:type_champ,
:libelle,
:description,
:mandatory,
:parent_id,
:private,
:drop_down_list_value,
:drop_down_other,
:drop_down_secondary_libelle,
:drop_down_secondary_description,
:piece_justificative_template,
editable_options: [
:cadastres,
:unesco,
:arretes_protection,
:conservatoire_littoral,
:reserves_chasse_faune_sauvage,
:reserves_biologiques,
:reserves_naturelles,
:natura_2000,
:zones_humides,
:znieff
])
params
.required(:type_de_champ)
.permit(:type_champ, :parent_id, :private, :libelle, :after_id)
end
def type_de_champ_update_params

View file

@ -4,7 +4,7 @@ module TurboStreamHelper
end
class TagBuilder < Turbo::Streams::TagBuilder
def dispatch(type, detail)
def dispatch(type, detail = {})
append_all('turbo-events', partial: 'layouts/turbo_event', locals: { type: type, detail: detail })
end

View file

@ -40,24 +40,26 @@ class ProcedureRevision < ApplicationRecord
def add_type_de_champ(params)
parent_stable_id = params.delete(:parent_id)
after_stable_id = params.delete(:after_id)
coordinate = {}
if parent_stable_id.present?
parent_coordinate, parent = coordinate_and_tdc(parent_stable_id)
parent_coordinate, _ = coordinate_and_tdc(parent_stable_id)
coordinate[:parent_id] = parent_coordinate.id
coordinate[:position] = children_of(parent).count
coordinate[:position] = last_position(parent_coordinate.revision_types_de_champ, after_stable_id)
elsif params[:private]
coordinate[:position] = revision_types_de_champ_private.count
coordinate[:position] = last_position(revision_types_de_champ_private, after_stable_id)
else
coordinate[:position] = revision_types_de_champ_public.count
coordinate[:position] = last_position(revision_types_de_champ_public, after_stable_id)
end
tdc = TypeDeChamp.new(params)
if tdc.save
coordinate[:type_de_champ] = tdc
revision_types_de_champ.create!(coordinate)
coordinate = revision_types_de_champ.create!(coordinate)
reorder(coordinate.siblings)
end
tdc
@ -83,6 +85,9 @@ class ProcedureRevision < ApplicationRecord
siblings.insert(position, siblings.delete_at(siblings.index(coordinate)))
reorder(siblings)
coordinate.reload
coordinate
end
def remove_type_de_champ(stable_id)
@ -95,6 +100,24 @@ class ProcedureRevision < ApplicationRecord
tdc.destroy_if_orphan
reorder(coordinate.siblings)
coordinate
end
def move_up_type_de_champ(stable_id)
coordinate, _ = coordinate_and_tdc(stable_id)
if coordinate.position > 0
move_type_de_champ(stable_id, coordinate.position - 1)
else
coordinate
end
end
def move_down_type_de_champ(stable_id)
coordinate, _ = coordinate_and_tdc(stable_id)
move_type_de_champ(stable_id, coordinate.position + 1)
end
def draft?
@ -162,6 +185,10 @@ class ProcedureRevision < ApplicationRecord
end
end
def coordinate_for(tdc)
revision_types_de_champ.find_by!(type_de_champ: tdc)
end
private
def compute_estimated_fill_duration
@ -189,7 +216,7 @@ class ProcedureRevision < ApplicationRecord
def reorder(siblings)
siblings.to_a.compact.each.with_index do |sibling, position|
sibling.update(position: position)
sibling.update_column(:position, position)
end
end
@ -426,4 +453,16 @@ class ProcedureRevision < ApplicationRecord
coordinate.update!(type_de_champ: cloned_type_de_champ)
cloned_type_de_champ
end
def last_position(siblings, after_stable_id = nil)
if after_stable_id.present?
siblings
.joins(:type_de_champ)
.find_by(types_de_champ: { stable_id: after_stable_id })
.position + 1
else
last = siblings.last
last.present? ? last.position + 1 : 0
end
end
end

View file

@ -16,6 +16,7 @@ class ProcedureRevisionTypeDeChamp < ApplicationRecord
belongs_to :parent, class_name: 'ProcedureRevisionTypeDeChamp', optional: true
has_many :revision_types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'ProcedureRevisionTypeDeChamp', inverse_of: :parent, dependent: :destroy
has_one :procedure, through: :revision
scope :root, -> { where(parent: nil) }
scope :ordered, -> { order(:position) }
scope :revision_ordered, -> { order(:revision_id) }
@ -28,6 +29,14 @@ class ProcedureRevisionTypeDeChamp < ApplicationRecord
parent_id.present?
end
def first?
position == 0
end
def last?
siblings.last == self
end
def siblings
if parent_id.present?
revision.revision_types_de_champ.where(parent_id: parent_id).ordered
@ -37,4 +46,19 @@ class ProcedureRevisionTypeDeChamp < ApplicationRecord
revision.revision_types_de_champ_public
end
end
def previous_sibling
index = siblings.index(self)
if index > 0
siblings[index - 1]
end
end
def block
if child?
parent
else
revision
end
end
end

View file

@ -0,0 +1,9 @@
- sibling = coordinate.previous_sibling
- if sibling.present?
= turbo_stream.after dom_id(sibling, :type_de_champ_editor) do
= render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, focused: true)
- else
= turbo_stream.prepend dom_id(coordinate.block, :types_de_champ_editor_block) do
= render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, focused: true)
= turbo_stream.dispatch 'sortable:sort'

View file

@ -0,0 +1,2 @@
- if @coordinate&.type_de_champ&.valid?
= render partial: 'insert', locals: { coordinate: @coordinate }

View file

@ -0,0 +1,4 @@
= turbo_stream.remove dom_id(@coordinate, :type_de_champ_editor)
= turbo_stream.dispatch 'sortable:sort'
= turbo_stream.morph dom_id(@coordinate.revision, :estimated_fill_duration) do
= render TypesDeChampEditor::EstimatedFillDurationComponent.new(revision: @coordinate.revision, is_annotation: @coordinate.private?)

View file

@ -0,0 +1,2 @@
= turbo_stream.remove dom_id(@coordinate, :type_de_champ_editor)
= render partial: 'insert', locals: { coordinate: @coordinate }

View file

@ -0,0 +1,2 @@
= turbo_stream.remove dom_id(@coordinate, :type_de_champ_editor)
= render partial: 'insert', locals: { coordinate: @coordinate }

View file

@ -0,0 +1,5 @@
- if @coordinate&.type_de_champ&.valid?
= turbo_stream.morph dom_id(@coordinate, :type_de_champ_editor) do
= render TypesDeChampEditor::ChampComponent.new(coordinate: @coordinate)
= turbo_stream.morph dom_id(@coordinate.revision, :estimated_fill_duration) do
= render TypesDeChampEditor::EstimatedFillDurationComponent.new(revision: @coordinate.revision, is_annotation: @coordinate.private?)

View file

@ -469,6 +469,8 @@ Rails.application.routes.draw do
end
member do
patch :move
patch :move_up
patch :move_down
end
end

View file

@ -1,7 +1,7 @@
describe Administrateurs::TypesDeChampController, type: :controller do
let(:admin) { create(:administrateur) }
describe '#types_de_champs editor api' do
describe '#types_de_champs editor' do
let(:procedure) { create(:procedure) }
before do
@ -17,12 +17,13 @@ describe Administrateurs::TypesDeChampController, type: :controller do
procedure_id: procedure.id,
type_de_champ: {
type_champ: type_champ,
libelle: 'Nouveau champ'
libelle: 'Nouveau champ',
private: false
}
}
}, format: :turbo_stream
end
it { expect(response).to have_http_status(:created) }
it { expect(response).to have_http_status(:ok) }
end
context "validate type_de_champ linked_drop_down_list" do
@ -33,12 +34,13 @@ describe Administrateurs::TypesDeChampController, type: :controller do
procedure_id: procedure.id,
type_de_champ: {
type_champ: type_champ,
libelle: 'Nouveau champ'
libelle: 'Nouveau champ',
private: false
}
}
}, format: :turbo_stream
end
it { expect(response).to have_http_status(:unprocessable_entity) }
it { expect(response).to have_http_status(:ok) }
end
context "create type_de_champ linked_drop_down_list" do
@ -50,12 +52,13 @@ describe Administrateurs::TypesDeChampController, type: :controller do
type_de_champ: {
type_champ: type_champ,
libelle: 'Nouveau champ',
drop_down_list_value: '--value--'
drop_down_list_value: '--value--',
private: false
}
}
}, format: :turbo_stream
end
it { expect(response).to have_http_status(:created) }
it { expect(response).to have_http_status(:ok) }
end
end
end