Merge pull request #3300 from tchak/champs-editor-repetition
Champs editor should handle repetition type
This commit is contained in:
commit
cb38fe754a
13 changed files with 148 additions and 55 deletions
|
@ -28,4 +28,12 @@
|
|||
&.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
}
|
||||
|
||||
.draggable-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
border: 1px solid $border-grey;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
|
@ -55,20 +51,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
|
||||
&.shift-left {
|
||||
margin-left: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
|
||||
.flex {
|
||||
&.section {
|
||||
padding: 10px 10px 0 10px;
|
||||
margin-bottom: 8px;
|
||||
|
|
|
@ -3,7 +3,7 @@ module NewAdministrateur
|
|||
before_action :retrieve_procedure, only: [:champs, :annotations, :update]
|
||||
before_action :procedure_locked?, only: [:champs, :annotations, :update]
|
||||
|
||||
TYPE_DE_CHAMP_ATTRIBUTES = [
|
||||
TYPE_DE_CHAMP_ATTRIBUTES_BASE = [
|
||||
:_destroy,
|
||||
:libelle,
|
||||
:description,
|
||||
|
@ -18,6 +18,11 @@ module NewAdministrateur
|
|||
drop_down_list_attributes: [:value]
|
||||
]
|
||||
|
||||
TYPE_DE_CHAMP_ATTRIBUTES = TYPE_DE_CHAMP_ATTRIBUTES_BASE.dup
|
||||
TYPE_DE_CHAMP_ATTRIBUTES << {
|
||||
types_de_champ_attributes: TYPE_DE_CHAMP_ATTRIBUTES_BASE
|
||||
}
|
||||
|
||||
def apercu
|
||||
@dossier = procedure_without_control.new_dossier
|
||||
@tab = apercu_tab
|
||||
|
@ -26,9 +31,9 @@ module NewAdministrateur
|
|||
def update
|
||||
if @procedure.update(procedure_params)
|
||||
flash.now.notice = if params[:procedure][:types_de_champ_attributes].present?
|
||||
'Champs enregistrés'
|
||||
'Formulaire mis à jour.'
|
||||
elsif params[:procedure][:types_de_champ_private_attributes].present?
|
||||
'Annotations enregistrés'
|
||||
'Annotations privées mises à jour.'
|
||||
else
|
||||
'Démarche enregistrée.'
|
||||
end
|
||||
|
|
|
@ -79,9 +79,16 @@ module ProcedureHelper
|
|||
types_de_champ
|
||||
end
|
||||
|
||||
TYPES_DE_CHAMP_INCLUDE = { drop_down_list: { only: :value } }
|
||||
TYPES_DE_CHAMP_BASE = {
|
||||
except: [:created_at, :updated_at, :stable_id, :type, :parent_id, :procedure_id, :private],
|
||||
methods: [:piece_justificative_template_filename, :piece_justificative_template_url],
|
||||
include: TYPES_DE_CHAMP_INCLUDE
|
||||
}
|
||||
TYPES_DE_CHAMP = TYPES_DE_CHAMP_BASE
|
||||
.merge(include: TYPES_DE_CHAMP_INCLUDE.merge(types_de_champ: TYPES_DE_CHAMP_BASE))
|
||||
|
||||
def types_de_champ_as_json(types_de_champ)
|
||||
types_de_champ.as_json(except: [:created_at, :updated_at],
|
||||
methods: [:piece_justificative_template_filename, :piece_justificative_template_url],
|
||||
include: { drop_down_list: { only: :value } })
|
||||
types_de_champ.as_json(TYPES_DE_CHAMP)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export default {
|
||||
props: ['state', 'update', 'index', 'item', 'prefix'],
|
||||
props: ['state', 'update', 'index', 'item'],
|
||||
computed: {
|
||||
isDirty() {
|
||||
return (
|
||||
|
@ -56,6 +56,9 @@ export default {
|
|||
isHeaderSection() {
|
||||
return this.typeChamp === 'header_section';
|
||||
},
|
||||
isRepetition() {
|
||||
return this.typeChamp === 'repetition';
|
||||
},
|
||||
options() {
|
||||
const options = this.item.options || {};
|
||||
for (let key of Object.keys(options)) {
|
||||
|
@ -69,6 +72,21 @@ export default {
|
|||
} else {
|
||||
return 'types_de_champ_attributes';
|
||||
}
|
||||
},
|
||||
typesDeChamp() {
|
||||
return this.item.types_de_champ;
|
||||
},
|
||||
typesDeChampOptions() {
|
||||
return this.state.typesDeChampOptions.filter(
|
||||
([, typeChamp]) => !EXCLUDE_FROM_REPETITION.includes(typeChamp)
|
||||
);
|
||||
},
|
||||
stateForRepetition() {
|
||||
return Object.assign({}, this.state, {
|
||||
typesDeChamp: this.typesDeChamp,
|
||||
typesDeChampOptions: this.typesDeChampOptions,
|
||||
prefix: `${this.state.prefix}[${this.attribute}][${this.index}]`
|
||||
});
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -103,14 +121,30 @@ export default {
|
|||
}
|
||||
},
|
||||
nameFor(name) {
|
||||
return `${this.prefix}[${this.attribute}][${this.index}][${name}]`;
|
||||
return `${this.state.prefix}[${this.attribute}][${this.index}][${name}]`;
|
||||
},
|
||||
elementIdFor(name) {
|
||||
return `${this.prefix}_${this.attribute}_${this.index}_${name}`;
|
||||
const prefix = this.state.prefix.replace(/\[/g, '_').replace(/\]/g, '');
|
||||
return `${prefix}_${this.attribute}_${this.index}_${name}`;
|
||||
},
|
||||
addChamp() {
|
||||
this.typesDeChamp.push({
|
||||
type_champ: 'text',
|
||||
drop_down_list: {},
|
||||
types_de_champ: [],
|
||||
options: {}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const EXCLUDE_FROM_REPETITION = [
|
||||
'carte',
|
||||
'dossier_link',
|
||||
'repetition',
|
||||
'siret'
|
||||
];
|
||||
|
||||
const PATHS_TO_WATCH = [
|
||||
'typeChamp',
|
||||
'libelle',
|
||||
|
|
|
@ -4,19 +4,23 @@
|
|||
<input type="hidden" :name="nameFor('_destroy')" value="true">
|
||||
</div>
|
||||
|
||||
<div class="draggable-item" v-else :class="itemClassName">
|
||||
<div class="row section head" :class="{ hr: !isHeaderSection }">
|
||||
<div class="draggable-item flex column justify-start" v-else :class="itemClassName">
|
||||
<div class="flex justify-start section head" :class="{ hr: !isHeaderSection }">
|
||||
<div class="handle">
|
||||
<img :src="state.dragIconUrl" alt="">
|
||||
</div>
|
||||
<div class="cell">
|
||||
<select :name="nameFor('type_champ')" v-model="typeChamp" class="small-margin small inline">
|
||||
<option v-for="option in state.typesDeChampOptions" :key="option[1]" :value="option[1]">
|
||||
{{ option[0] }}
|
||||
</option>
|
||||
<select
|
||||
:id="elementIdFor('type_champ')"
|
||||
:name="nameFor('type_champ')"
|
||||
v-model="typeChamp"
|
||||
class="small-margin small inline">
|
||||
<option v-for="option in state.typesDeChampOptions" :key="option[1]" :value="option[1]">
|
||||
{{ option[0] }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row delete">
|
||||
<div class="flex justify-start delete">
|
||||
<div v-if="isDirty" class="error-message">
|
||||
<span v-if="isInvalid" class="content">
|
||||
Le libellé doit être rempli.
|
||||
|
@ -36,8 +40,8 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row section" :class="{ hr: isDropDown || isFile || isCarte }">
|
||||
<div class="column shift-left">
|
||||
<div class="flex justify-start section" :class="{ hr: isDropDown || isFile || isCarte }">
|
||||
<div class="flex column justify-start shift-left">
|
||||
<div class="cell libelle">
|
||||
<label :for="elementIdFor('libelle')">
|
||||
Libellé
|
||||
|
@ -65,7 +69,7 @@
|
|||
value="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="flex justify-start">
|
||||
<div class="cell" v-show="!isHeaderSection">
|
||||
<label :for="elementIdFor('description')">
|
||||
Description
|
||||
|
@ -81,7 +85,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row section shift-left" v-show="!isHeaderSection">
|
||||
<div class="flex justify-start section shift-left" v-show="!isHeaderSection">
|
||||
<div class="cell" v-show="isDropDown">
|
||||
<label :for="elementIdFor('drop_down_list')">
|
||||
Liste déroulante
|
||||
|
@ -154,6 +158,26 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow cell" v-show="isRepetition">
|
||||
<Draggable :list="typesDeChamp" :options="{handle:'.handle'}">
|
||||
<DraggableItem
|
||||
v-for="(item, index) in typesDeChamp"
|
||||
:state="stateForRepetition"
|
||||
:update="update"
|
||||
:index="index"
|
||||
:item="item"
|
||||
:key="item.id" />
|
||||
</Draggable>
|
||||
|
||||
<button class="button" @click.prevent="addChamp">
|
||||
<template v-if="state.isAnnotation">
|
||||
Ajouter une annotation
|
||||
</template>
|
||||
<template v-else>
|
||||
Ajouter un champ
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<input type="hidden" :name="nameFor('order_place')" :value="index">
|
||||
|
|
|
@ -5,6 +5,7 @@ export default {
|
|||
this.state.typesDeChamp.push({
|
||||
type_champ: 'text',
|
||||
drop_down_list: {},
|
||||
types_de_champ: [],
|
||||
options: {}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<Draggable :list="state.typesDeChamp" :options="{handle:'.handle'}">
|
||||
<DraggableItem
|
||||
v-for="(item, index) in state.typesDeChamp"
|
||||
prefix="procedure"
|
||||
:state="state"
|
||||
:update="update"
|
||||
:index="index"
|
||||
|
|
|
@ -26,7 +26,8 @@ function initEditor(el) {
|
|||
isAnnotation: el.dataset.type === 'annotation',
|
||||
unsavedItems: new Set(),
|
||||
unsavedInvalidItems: new Set(),
|
||||
version: 1
|
||||
version: 1,
|
||||
prefix: 'procedure'
|
||||
};
|
||||
|
||||
new Vue({
|
||||
|
|
|
@ -35,7 +35,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
belongs_to :procedure
|
||||
|
||||
belongs_to :parent, class_name: 'TypeDeChamp'
|
||||
has_many :types_de_champ, foreign_key: :parent_id, class_name: 'TypeDeChamp', dependent: :destroy
|
||||
has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', dependent: :destroy
|
||||
|
||||
store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles, :old_pj
|
||||
|
||||
|
@ -84,7 +84,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
has_one_attached :piece_justificative_template
|
||||
|
||||
accepts_nested_attributes_for :drop_down_list, update_only: true
|
||||
accepts_nested_attributes_for :types_de_champ, allow_destroy: true
|
||||
accepts_nested_attributes_for :types_de_champ, reject_if: proc { |attributes| attributes['libelle'].blank? }, allow_destroy: true
|
||||
|
||||
validates :libelle, presence: true, allow_blank: false, allow_nil: false
|
||||
validates :type_champ, presence: true, allow_blank: false, allow_nil: false
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<%= render_flash timeout: 6000, fixed: true %>
|
||||
|
||||
<%= fire_event(:ProcedureUpdated, procedure_data(@procedure)) %>
|
||||
<%= fire_event(:ProcedureUpdated, procedure_data(@procedure.reload)) %>
|
||||
|
|
|
@ -105,7 +105,7 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
|
|||
end
|
||||
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libelle de champ'
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
|
||||
within '.footer' do
|
||||
click_on 'Ajouter un champ'
|
||||
|
@ -135,7 +135,7 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
|
|||
click_on 'Ajouter un champ'
|
||||
end
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libelle de champ'
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
|
||||
click_on Procedure.last.libelle
|
||||
click_on 'onglet-pieces'
|
||||
|
|
|
@ -5,6 +5,7 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
let(:procedure) { create(:procedure) }
|
||||
|
||||
before do
|
||||
Flipflop::FeatureSet.current.test!.switch!(:champ_repetition, true)
|
||||
login_as administrateur, scope: :administrateur
|
||||
visit champs_procedure_path(procedure)
|
||||
end
|
||||
|
@ -15,14 +16,14 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
end
|
||||
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
|
||||
page.refresh
|
||||
within '.footer' do
|
||||
click_on 'Enregistrer'
|
||||
end
|
||||
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
end
|
||||
|
||||
it "Add multiple champs" do
|
||||
|
@ -34,7 +35,7 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
end
|
||||
expect(page).not_to have_content('Le libellé doit être rempli.')
|
||||
expect(page).not_to have_content('Modifications non sauvegardées.')
|
||||
expect(page).not_to have_content('Champs enregistrés')
|
||||
expect(page).not_to have_content('Formulaire mis à jour')
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ 0'
|
||||
|
||||
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
|
||||
|
@ -44,7 +45,7 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
|
||||
expect(page).to have_content('Le libellé doit être rempli.')
|
||||
expect(page).to have_content('Modifications non sauvegardées.')
|
||||
expect(page).not_to have_content('Champs enregistrés')
|
||||
expect(page).not_to have_content('Formulaire mis à jour')
|
||||
fill_in 'procedure_types_de_champ_attributes_2_libelle', with: 'libellé de champ 2'
|
||||
|
||||
within '.draggable-item-3' do
|
||||
|
@ -53,12 +54,12 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
|
||||
expect(page).to have_content('Le libellé doit être rempli.')
|
||||
expect(page).to have_content('Modifications non sauvegardées.')
|
||||
expect(page).not_to have_content('Champs enregistrés')
|
||||
expect(page).not_to have_content('Formulaire mis à jour')
|
||||
fill_in 'procedure_types_de_champ_attributes_1_libelle', with: 'libellé de champ 1'
|
||||
|
||||
expect(page).not_to have_content('Le libellé doit être rempli.')
|
||||
expect(page).not_to have_content('Modifications non sauvegardées.')
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
page.refresh
|
||||
|
||||
expect(page).to have_content('Supprimer', count: 3)
|
||||
|
@ -69,11 +70,11 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
click_on 'Ajouter un champ'
|
||||
end
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
page.refresh
|
||||
|
||||
click_on 'Supprimer'
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
expect(page).not_to have_content('Supprimer')
|
||||
page.refresh
|
||||
|
||||
|
@ -87,9 +88,39 @@ feature 'As an administrateur I edit procedure', js: true do
|
|||
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_description')
|
||||
fill_in 'procedure_types_de_champ_attributes_0_description', with: 'déscription du champ'
|
||||
expect(page).to have_content('Le libellé doit être rempli.')
|
||||
expect(page).not_to have_content('Champs enregistrés')
|
||||
expect(page).not_to have_content('Formulaire mis à jour')
|
||||
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
|
||||
expect(page).to have_content('Champs enregistrés')
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
end
|
||||
|
||||
it "Add repetition champ" do
|
||||
within '.footer' do
|
||||
click_on 'Ajouter un champ'
|
||||
end
|
||||
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
|
||||
select('Bloc répétable', from: 'procedure_types_de_champ_attributes_0_type_champ')
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
|
||||
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
page.refresh
|
||||
|
||||
within '.flex-grow' do
|
||||
click_on 'Ajouter un champ'
|
||||
end
|
||||
|
||||
fill_in 'procedure_types_de_champ_attributes_0_types_de_champ_attributes_0_libelle', with: 'libellé de champ 1'
|
||||
|
||||
expect(page).to have_content('Formulaire mis à jour')
|
||||
expect(page).to have_content('Supprimer', count: 2)
|
||||
|
||||
within '.footer' do
|
||||
click_on 'Ajouter un champ'
|
||||
end
|
||||
|
||||
select('Bloc répétable', from: 'procedure_types_de_champ_attributes_1_type_champ')
|
||||
fill_in 'procedure_types_de_champ_attributes_1_libelle', with: 'libellé de champ 2'
|
||||
|
||||
expect(page).to have_content('Supprimer', count: 3)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue