From 61839ef1acc2d442252bf29f61b2d35cc1485d79 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Jul 2022 12:23:46 +0200 Subject: [PATCH 01/17] add logic condition_split --- app/models/logic.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/logic.rb b/app/models/logic.rb index 992f0f800..a69c979f3 100644 --- a/app/models/logic.rb +++ b/app/models/logic.rb @@ -68,6 +68,10 @@ module Logic end end + def self.split_condition(condition) + [condition.left, condition.class.name, condition.right] + end + def ds_eq(left, right) = Logic::Eq.new(left, right) def greater_than(left, right) = Logic::GreaterThan.new(left, right) From e2a236b73d34f24acadfdf7f3938843b32f11697 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 6 Jul 2022 09:55:08 +0200 Subject: [PATCH 02/17] add condition_component --- .../stylesheets/conditions_component.scss | 62 +++++++ .../stylesheets/procedure_champs_editor.scss | 2 +- .../types_de_champ/conditions_component.rb | 151 ++++++++++++++++ .../conditions_component.html.haml | 26 +++ config/locales/models/logic/fr.yml | 6 + .../conditions_component_spec.rb | 162 ++++++++++++++++++ 6 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 app/assets/stylesheets/conditions_component.scss create mode 100644 app/components/types_de_champ/conditions_component.rb create mode 100644 app/components/types_de_champ/conditions_component/conditions_component.html.haml create mode 100644 spec/components/types_de_champ/conditions_component_spec.rb diff --git a/app/assets/stylesheets/conditions_component.scss b/app/assets/stylesheets/conditions_component.scss new file mode 100644 index 000000000..7cfcd62cb --- /dev/null +++ b/app/assets/stylesheets/conditions_component.scss @@ -0,0 +1,62 @@ +@import "colors"; +@import "constants"; + +.conditionnel { + + .condition-table { + table-layout: fixed; + + .far-left { + width: 100px; + } + + .target { + width: 350px; + + select { + width: 100%; + } + } + + .operator { + width: 250px; + + select { + width: 100%; + } + } + + .value { + width: 200px; + } + + .delete-column { + width: 50px; + } + } + + th { + text-align: left; + padding: $default-spacer; + + } + + td { + padding: $default-spacer; + + input, + select { + margin-bottom: 0; + } + + input[type=number] { + display: inline-block; + margin-bottom: 0; + } + + input.alert, + select.alert { + border-color: $dark-red; + } + } +} diff --git a/app/assets/stylesheets/procedure_champs_editor.scss b/app/assets/stylesheets/procedure_champs_editor.scss index 93beefd4a..404e90890 100644 --- a/app/assets/stylesheets/procedure_champs_editor.scss +++ b/app/assets/stylesheets/procedure_champs_editor.scss @@ -93,7 +93,7 @@ .flex { &.section { - padding: 10px 10px 0 10px; + padding: $default-spacer $default-spacer 0; margin-bottom: 8px; } diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb new file mode 100644 index 000000000..b76d0f3e4 --- /dev/null +++ b/app/components/types_de_champ/conditions_component.rb @@ -0,0 +1,151 @@ +class TypesDeChamp::ConditionsComponent < ApplicationComponent + include Logic + + def initialize(tdc:, upper_tdcs:, procedure_id:) + @tdc, @condition, @upper_tdcs = tdc, tdc.condition, upper_tdcs + @procedure_id = procedure_id + end + + private + + def rows + condition_per_row.map { |c| Logic.split_condition(c) } + end + + def condition_per_row + if [And, Or].include?(@condition.class) + @condition.operands + else + [@condition].compact + end + end + + def logic_conditionnel_button + if @condition.nil? + submit_tag('cliquer pour activer', formaction: add_row_admin_procedure_condition_path(@procedure_id, @tdc.id)) + else + submit_tag( + 'cliquer pour désactiver', + formmethod: 'delete', + formnovalidate: true, + data: { confirm: "La logique conditionnelle appliquée à ce champ sera désactivé.\nVoulez-vous continuer ?" } + ) + end + end + + def far_left_tag(row_number) + if row_number == 0 + 'Afficher si' + elsif row_number == 1 + select_tag( + "#{input_prefix}[top_operator_name]", + options_for_select([['Et', And.name], ['Ou', Or.name]], @condition.class.name) + ) + end + end + + def left_operand_tag(targeted_champ, row_index) + select_tag( + input_name_for('targeted_champ'), + options_for_select(available_targets, targeted_champ.to_json), + onchange: "this.form.action = this.form.action + '/change_targeted_champ?row_index=#{row_index}'", + id: input_id_for('targeted_champ', row_index) + ) + end + + def available_targets + targets = @upper_tdcs + .filter { |tdc| ChampValue::MANAGED_TYPE_DE_CHAMP.values.include?(tdc.type_champ) } + .map do |tdc| + [tdc.libelle, champ_value(tdc.stable_id).to_json] + end + + if targets.present? + targets.unshift(['Sélectionner', empty.to_json]) + end + + targets + end + + def operator_tag(operator_name, targeted_champ, row_index) + select_tag( + input_name_for('operator_name'), + options_for_select(available_operators(targeted_champ), operator_name), + id: input_id_for('operator_name', row_index) + ) + end + + def available_operators(left) + case left.type + when ChampValue::CHAMP_VALUE_TYPE.fetch(:boolean) + [ + ['Est', Eq.name] + ] + when ChampValue::CHAMP_VALUE_TYPE.fetch(:empty) + [ + ['Est', Eq.name] + ] + when ChampValue::CHAMP_VALUE_TYPE.fetch(:enum) + [ + ['Est', Eq.name] + ] + when ChampValue::CHAMP_VALUE_TYPE.fetch(:number) + [Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq] + .map(&:name) + .map { |name| [t(name, scope: 'logic.operators'), name] } + else + [] + end + end + + def right_operand_tag(left, right, row_index) + case left.type + when :boolean + select_tag( + input_name_for('value'), + options_for_select([['Oui', constant(true).to_json], ['Non', constant(false).to_json]], right.to_json), + id: input_id_for('value', row_index) + ) + when :empty + select_tag( + input_name_for('value'), + options_for_select([['Sélectionner', empty.to_json]]), + id: input_id_for('value', row_index) + ) + when :enum + select_tag( + input_name_for('value'), + options_for_select(left.options, right.value), + id: input_id_for('value', row_index) + ) + when :number + number_field_tag(input_name_for('value'), right.value, required: true, id: input_id_for('value', row_index)) + else + number_field_tag(input_name_for('value'), '', id: input_id_for('value', row_index)) + end + end + + def add_condition_tag + submit_tag('Ajouter une condition', formaction: add_row_condition_path(@tdc.id)) + end + + def delete_condition_tag(row_index) + submit_tag('X', formaction: delete_row_condition_path(@tdc.id, row_index: row_index)) + end + + def render? + @condition.present? || available_targets.any? + end + + def input_name_for(name) + "#{input_prefix}[rows][][#{name}]" + end + + def input_id_for(name, row_index) + "#{@tdc.id}-#{name}-#{row_index}" + end + + def input_prefix + 'type_de_champ[condition_form]' + end +end diff --git a/app/components/types_de_champ/conditions_component/conditions_component.html.haml b/app/components/types_de_champ/conditions_component/conditions_component.html.haml new file mode 100644 index 000000000..f28edcfc2 --- /dev/null +++ b/app/components/types_de_champ/conditions_component/conditions_component.html.haml @@ -0,0 +1,26 @@ +.flex.justify-start.section{ id: dom_id(@tdc, :conditions) } + = form_with url: admin_procedure_condition_path(@procedure_id, @tdc), method: :patch, class: 'form width-100' do |f| + .conditionnel.mt-2.width-100 + .flex + %p.mr-2 Logique conditionnelle + = logic_conditionnel_button + + - if @condition.present? + %table.condition-table.mt-2.width-100 + %thead + %tr + %th.far-left + %th.target Champ Cible + %th.operator Opérateur + %th.value Valeur + %th.delete-column + %tbody + - rows.each.with_index do |(targeted_champ, operator_name, value), row_index| + %tr + %td.far-left= far_left_tag(row_index) + %td.target= left_operand_tag(targeted_champ, row_index) + %td.operator= operator_tag(operator_name, targeted_champ, row_index) + %td.value= right_operand_tag(targeted_champ, value, row_index) + %td.delete-column= delete_condition_tag(row_index) + + .flex.justify-end.mt-2= add_condition_tag diff --git a/config/locales/models/logic/fr.yml b/config/locales/models/logic/fr.yml index bb40dad9c..3f48dadd9 100644 --- a/config/locales/models/logic/fr.yml +++ b/config/locales/models/logic/fr.yml @@ -1,3 +1,9 @@ fr: logic: empty: un membre vide + operators: + 'Logic::LessThan': Inférieur à + 'Logic::LessThanEq': Inférieur ou égal à + 'Logic::Eq': Égal à + 'Logic::GreaterThan': Supérieur à + 'Logic::GreaterThanEq': Supérieur ou égal à diff --git a/spec/components/types_de_champ/conditions_component_spec.rb b/spec/components/types_de_champ/conditions_component_spec.rb new file mode 100644 index 000000000..8b69afb39 --- /dev/null +++ b/spec/components/types_de_champ/conditions_component_spec.rb @@ -0,0 +1,162 @@ +describe TypesDeChamp::ConditionsComponent, type: :component do + include Logic + + describe 'render' do + let(:tdc) { create(:type_de_champ, condition: condition) } + let(:condition) { nil } + let(:upper_tdcs) { [] } + + before { render_inline(described_class.new(tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: 123)) } + + context 'when there are no upper tdc' do + it { expect(page).not_to have_text('Logique conditionnelle') } + end + + context 'when there are upper tdcs but not managed' do + let(:upper_tdcs) { [build(:type_de_champ_address)] } + + it { expect(page).not_to have_text('Logique conditionnelle') } + end + + context 'when there are upper tdc but no condition to display' do + let(:upper_tdcs) { [build(:type_de_champ_integer_number)] } + + it do + expect(page).to have_text('Logique conditionnelle') + expect(page).to have_button('cliquer pour activer') + expect(page).not_to have_selector('table') + end + end + + context 'when there are upper tdc and a condition' do + let(:upper_tdc) { create(:type_de_champ_number) } + let(:upper_tdcs) { [upper_tdc] } + + context 'and one condition' do + let(:condition) { ds_eq(champ_value(upper_tdc.stable_id), constant(1)) } + + it do + expect(page).to have_button('cliquer pour désactiver') + expect(page).to have_selector('table') + expect(page).to have_selector('tbody > tr', count: 1) + end + end + + context 'focus one row' do + context 'empty' do + let(:condition) { empty_operator(empty, empty) } + + it do + expect(page).to have_select('type_de_champ[condition_form][rows][][operator_name]', options: ['Est']) + expect(page).to have_select('type_de_champ[condition_form][rows][][value]', options: ['Sélectionner']) + end + end + + context 'number' do + let(:condition) { empty_operator(constant(1), constant(0)) } + + it do + expect(page).to have_select('type_de_champ[condition_form][rows][][operator_name]', with_options: ['Égal à']) + expect(page).to have_selector('input[name="type_de_champ[condition_form][rows][][value]"][value=0]') + end + end + + context 'boolean' do + let(:condition) { empty_operator(constant(true), constant(true)) } + + it do + expect(page).to have_select('type_de_champ[condition_form][rows][][operator_name]', with_options: ['Est']) + expect(page).to have_select('type_de_champ[condition_form][rows][][value]', options: ['Oui', 'Non']) + end + end + + context 'enum' do + let(:drop_down) { create(:type_de_champ_drop_down_list) } + let(:upper_tdcs) { [drop_down] } + let(:condition) { empty_operator(champ_value(drop_down.stable_id), constant(true)) } + + it do + expect(page).to have_select('type_de_champ[condition_form][rows][][operator_name]', with_options: ['Est']) + expect(page).to have_select('type_de_champ[condition_form][rows][][value]', options: ['val1', 'val2', 'val3']) + end + end + end + + context 'and 2 conditions' do + let(:condition) { ds_and([empty_operator(empty, empty), empty_operator(empty, empty)]) } + + it do + expect(page).to have_selector('tbody > tr', count: 2) + expect(page).to have_select("type_de_champ_condition_form_top_operator_name", selected: "Et", options: ['Et', 'Ou']) + end + end + + context 'when there are 3 conditions' do + let(:upper_tdc) { create(:type_de_champ_number) } + let(:upper_tdcs) { [upper_tdc] } + + let(:condition) do + ds_or([ + ds_eq(champ_value(upper_tdc.stable_id), constant(1)), + ds_eq(champ_value(upper_tdc.stable_id), empty), + greater_than(champ_value(upper_tdc.stable_id), constant(3)) + ]) + end + + it do + expect(page).to have_selector('tbody > tr', count: 3) + expect(page).to have_select("type_de_champ_condition_form_top_operator_name", selected: "Ou", options: ['Et', 'Ou']) + end + end + end + end + + describe '.rows' do + let(:tdc) { build(:type_de_champ, condition: condition) } + let(:condition) { nil } + + subject { described_class.new(tdc: tdc, upper_tdcs: [], procedure_id: 123).send(:rows) } + + context 'when there is one condition' do + let(:condition) { ds_eq(empty, constant(1)) } + + it { is_expected.to eq([[empty, Logic::Eq.name, constant(1)]]) } + end + + context 'when there are 2 conditions' do + let(:condition) { ds_and([ds_eq(empty, constant(1)), ds_eq(empty, empty)]) } + + let(:expected) do + [ + [empty, Logic::Eq.name, constant(1)], + [empty, Logic::Eq.name, empty] + ] + end + + it { is_expected.to eq(expected) } + end + + context 'when there are 3 conditions' do + let(:upper_tdc) { create(:type_de_champ_number) } + let(:upper_tdcs) { [upper_tdc] } + + let(:condition) do + ds_or([ + ds_eq(champ_value(upper_tdc.stable_id), constant(1)), + ds_eq(champ_value(upper_tdc.stable_id), empty), + greater_than(champ_value(upper_tdc.stable_id), constant(3)) + ]) + end + + let(:expected) do + [ + [champ_value(upper_tdc.stable_id), Logic::Eq.name, constant(1)], + [champ_value(upper_tdc.stable_id), Logic::Eq.name, empty], + [champ_value(upper_tdc.stable_id), Logic::GreaterThan.name, constant(3)] + ] + end + + it { is_expected.to eq(expected) } + end + end +end From 03e9e95d56aa17f8c1efaea4ba30531e7886b992 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 27 Jun 2022 15:09:27 +0200 Subject: [PATCH 03/17] condition component manage invalid operator --- .../types_de_champ/conditions_component.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index b76d0f3e4..d5408e960 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -68,14 +68,23 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def operator_tag(operator_name, targeted_champ, row_index) + ops = compatibles_operators(targeted_champ) + + current_operator_valid = ops.map(&:second).include?(operator_name) + + if !current_operator_valid + ops.unshift(['Sélectionner', EmptyOperator.name]) + end + select_tag( input_name_for('operator_name'), - options_for_select(available_operators(targeted_champ), operator_name), - id: input_id_for('operator_name', row_index) + options_for_select(ops, selected: operator_name), + id: input_id_for('operator_name', row_index), + class: { alert: !current_operator_valid } ) end - def available_operators(left) + def compatibles_operators(left) case left.type when ChampValue::CHAMP_VALUE_TYPE.fetch(:boolean) [ From db4b7fc34435ee302a1e8228f5d86960e0b31271 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 27 Jun 2022 15:51:54 +0200 Subject: [PATCH 04/17] condition component manage invalid value --- .../types_de_champ/conditions_component.rb | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index d5408e960..08343565b 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -92,7 +92,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:empty) [ - ['Est', Eq.name] + ['Est', EmptyOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:enum) [ @@ -108,12 +108,21 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def right_operand_tag(left, right, row_index) + right_valid = current_right_valid?(left, right) + case left.type when :boolean + options = [['Oui', constant(true).to_json], ['Non', constant(false).to_json]] + + if !right_valid + options.unshift(['Sélectionner', empty]) + end + select_tag( input_name_for('value'), - options_for_select([['Oui', constant(true).to_json], ['Non', constant(false).to_json]], right.to_json), - id: input_id_for('value', row_index) + options_for_select(options, right.to_json), + id: input_id_for('value', row_index), + class: right_valid ? nil : 'alert' ) when :empty select_tag( @@ -122,18 +131,42 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent id: input_id_for('value', row_index) ) when :enum + options = left.options + + if !right_valid + options.unshift(['Sélectionner', empty]) + end + select_tag( input_name_for('value'), - options_for_select(left.options, right.value), - id: input_id_for('value', row_index) + options_for_select(options, right.value), + id: input_id_for('value', row_index), + class: right_valid ? nil : 'alert' ) when :number - number_field_tag(input_name_for('value'), right.value, required: true, id: input_id_for('value', row_index)) + number_field_tag( + input_name_for('value'), + right.value, + required: true, + id: input_id_for('value', row_index), + class: right_valid ? nil : 'alert' + ) else number_field_tag(input_name_for('value'), '', id: input_id_for('value', row_index)) end end + def current_right_valid?(left, right) + case [left.type, right.type] + in [:boolean, :boolean] | [:number, :number] | [:empty, :empty] + true + in [:enum, :string] + left.options.include?(right.value) + else + false + end + end + def add_condition_tag submit_tag('Ajouter une condition', formaction: add_row_condition_path(@tdc.id)) end From 30859774e416a16630a408aa83d778d3c7bb96ed Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 28 Jun 2022 12:52:03 +0200 Subject: [PATCH 05/17] condition component manage invalid target --- .../types_de_champ/conditions_component.rb | 26 ++++++++++--------- .../conditions_component_spec.rb | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 08343565b..8a4d338a6 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -45,26 +45,28 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def left_operand_tag(targeted_champ, row_index) + current_target_valid = targets.map(&:second).include?(targeted_champ.to_json) + + selected_target = current_target_valid ? targeted_champ.to_json : empty.to_json + select_tag( input_name_for('targeted_champ'), - options_for_select(available_targets, targeted_champ.to_json), + options_for_select(targets, selected_target), onchange: "this.form.action = this.form.action + '/change_targeted_champ?row_index=#{row_index}'", - id: input_id_for('targeted_champ', row_index) + id: input_id_for('targeted_champ', row_index), + class: { alert: !current_target_valid } ) end + def targets + available_targets + .then { |targets| targets.unshift(['Sélectionner', empty.to_json]) } + end + def available_targets - targets = @upper_tdcs + @upper_tdcs .filter { |tdc| ChampValue::MANAGED_TYPE_DE_CHAMP.values.include?(tdc.type_champ) } - .map do |tdc| - [tdc.libelle, champ_value(tdc.stable_id).to_json] - end - - if targets.present? - targets.unshift(['Sélectionner', empty.to_json]) - end - - targets + .map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] } end def operator_tag(operator_name, targeted_champ, row_index) diff --git a/spec/components/types_de_champ/conditions_component_spec.rb b/spec/components/types_de_champ/conditions_component_spec.rb index 8b69afb39..d93c3a7c6 100644 --- a/spec/components/types_de_champ/conditions_component_spec.rb +++ b/spec/components/types_de_champ/conditions_component_spec.rb @@ -77,7 +77,7 @@ describe TypesDeChamp::ConditionsComponent, type: :component do it do expect(page).to have_select('type_de_champ[condition_form][rows][][operator_name]', with_options: ['Est']) - expect(page).to have_select('type_de_champ[condition_form][rows][][value]', options: ['val1', 'val2', 'val3']) + expect(page).to have_select('type_de_champ[condition_form][rows][][value]', options: ['Sélectionner', 'val1', 'val2', 'val3']) end end end From bf27a5ffc45a390b4cf21dd0157f758a62d64081 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 28 Jun 2022 13:03:11 +0200 Subject: [PATCH 06/17] style delete row button --- app/assets/stylesheets/conditions_component.scss | 6 ++++++ app/components/types_de_champ/conditions_component.rb | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/conditions_component.scss b/app/assets/stylesheets/conditions_component.scss index 7cfcd62cb..9d2317a0d 100644 --- a/app/assets/stylesheets/conditions_component.scss +++ b/app/assets/stylesheets/conditions_component.scss @@ -32,6 +32,12 @@ .delete-column { width: 50px; + + button { + background: none; + border: none; + cursor: pointer; + } } } diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 8a4d338a6..75b2e5e05 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -174,7 +174,12 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def delete_condition_tag(row_index) - submit_tag('X', formaction: delete_row_condition_path(@tdc.id, row_index: row_index)) + tag.button( + tag.span('', class: 'icon delete') + tag.span('Supprimer la ligne', class: 'sr-only'), + formaction: delete_row_admin_procedure_condition_path(@procedure_id, @tdc.id, row_index: row_index), + formmethod: 'delete', + formnovalidate: true + ) end def render? From cecf21050321688a297e37aea44e07b81d146030 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Tue, 28 Jun 2022 12:39:05 +0200 Subject: [PATCH 07/17] style add row button --- app/assets/stylesheets/conditions_component.scss | 9 +++++++++ app/components/types_de_champ/conditions_component.rb | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/conditions_component.scss b/app/assets/stylesheets/conditions_component.scss index 9d2317a0d..152eb8c0a 100644 --- a/app/assets/stylesheets/conditions_component.scss +++ b/app/assets/stylesheets/conditions_component.scss @@ -65,4 +65,13 @@ border-color: $dark-red; } } + + .add-row { + background: none; + border: none; + cursor: pointer; + font-size: 16px; + line-height: 25px; + margin: 0 $default-padding $default-padding; + } } diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 75b2e5e05..a9eaf4efc 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -170,7 +170,12 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def add_condition_tag - submit_tag('Ajouter une condition', formaction: add_row_condition_path(@tdc.id)) + tag.button( + tag.span('', class: 'icon add') + tag.span("Ajouter une condition"), + formaction: add_row_admin_procedure_condition_path(@procedure_id, @tdc.id), + formnovalidate: true, + class: 'add-row' + ) end def delete_condition_tag(row_index) From 1131a5c83eb9741cb2a59ce34ab121215cbcf739 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Jul 2022 12:26:14 +0200 Subject: [PATCH 08/17] condition component error --- .../stylesheets/conditions_component.scss | 9 ++++ .../conditions_component.html.haml | 2 + .../conditions_errors_component.rb | 34 +++++++++++++++ .../conditions_errors_component.fr.yml | 6 +++ .../conditions_errors_component.html.haml | 2 + .../conditions_errors_component_spec.rb | 43 +++++++++++++++++++ 6 files changed, 96 insertions(+) create mode 100644 app/components/types_de_champ/conditions_errors_component.rb create mode 100644 app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml create mode 100644 app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml create mode 100644 spec/components/types_de_champ/conditions_errors_component_spec.rb diff --git a/app/assets/stylesheets/conditions_component.scss b/app/assets/stylesheets/conditions_component.scss index 152eb8c0a..4633531bd 100644 --- a/app/assets/stylesheets/conditions_component.scss +++ b/app/assets/stylesheets/conditions_component.scss @@ -3,6 +3,15 @@ .conditionnel { + .condition-error { + background: $background-red; + margin: ($default-spacer) (-$default-spacer); + + ul { + padding: $default-spacer; + } + } + .condition-table { table-layout: fixed; diff --git a/app/components/types_de_champ/conditions_component/conditions_component.html.haml b/app/components/types_de_champ/conditions_component/conditions_component.html.haml index f28edcfc2..871cb2e9b 100644 --- a/app/components/types_de_champ/conditions_component/conditions_component.html.haml +++ b/app/components/types_de_champ/conditions_component/conditions_component.html.haml @@ -5,6 +5,8 @@ %p.mr-2 Logique conditionnelle = logic_conditionnel_button + = render TypesDeChamp::ConditionsErrorsComponent.new(conditions: condition_per_row, upper_tdcs: @upper_tdcs) + - if @condition.present? %table.condition-table.mt-2.width-100 %thead diff --git a/app/components/types_de_champ/conditions_errors_component.rb b/app/components/types_de_champ/conditions_errors_component.rb new file mode 100644 index 000000000..c9d706145 --- /dev/null +++ b/app/components/types_de_champ/conditions_errors_component.rb @@ -0,0 +1,34 @@ +class TypesDeChamp::ConditionsErrorsComponent < ApplicationComponent + def initialize(conditions:, upper_tdcs:) + @conditions, @upper_tdcs = conditions, upper_tdcs + end + + private + + def errors + @conditions + .filter { |condition| condition.errors(@upper_tdcs.map(&:stable_id)).present? } + .map { |condition| row_error(Logic.split_condition(condition)) } + .uniq + .map { |message| tag.li(message) } + .then { |lis| tag.ul(lis.reduce(&:+)) } + end + + def row_error((left, operator_name, right)) + targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == left.stable_id } + + if targeted_champ.nil? + "Un champ cible n'est plus disponible. Il est soit supprimé, soit déplacé en dessous de ce champ." + elsif left.type == :unmanaged + "Le champ « #{targeted_champ.libelle} » de type #{targeted_champ.type_champ} ne peut pas être utilisé comme champ cible." + else + "Le champ « #{targeted_champ.libelle} » est #{t(left.type, scope: '.type')}. Il ne peut pas être #{t(operator_name, scope: 'logic.operators').downcase} #{right.to_s.downcase}." + end + end + + def render? + @conditions + .filter { |condition| condition.errors(@upper_tdcs.map(&:stable_id)).present? } + .present? + end +end diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml new file mode 100644 index 000000000..213de5ed8 --- /dev/null +++ b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml @@ -0,0 +1,6 @@ +--- +fr: + type: + number: un nombre + string: un texte + boolean: soit oui, soit non diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml new file mode 100644 index 000000000..b0e3dbce7 --- /dev/null +++ b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml @@ -0,0 +1,2 @@ +.condition-error + = errors diff --git a/spec/components/types_de_champ/conditions_errors_component_spec.rb b/spec/components/types_de_champ/conditions_errors_component_spec.rb new file mode 100644 index 000000000..4a9bc8532 --- /dev/null +++ b/spec/components/types_de_champ/conditions_errors_component_spec.rb @@ -0,0 +1,43 @@ +describe TypesDeChamp::ConditionsErrorsComponent, type: :component do + include Logic + + describe 'render' do + let(:conditions) { [] } + let(:upper_tdcs) { [] } + + before { render_inline(described_class.new(conditions: conditions, upper_tdcs: upper_tdcs)) } + + context 'when there are no condition' do + it { expect(page).to have_no_css('.condition-error') } + end + + context 'when the targeted_champ is not available' do + let(:tdc) { create(:type_de_champ_integer_number) } + let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant(1))] } + + it do + expect(page).to have_css('.condition-error') + expect(page).to have_content("Un champ cible n'est plus disponible") + end + end + + context 'when the targeted_champ is unmanaged' do + let(:tdc) { create(:type_de_champ_address) } + let(:upper_tdcs) { [tdc] } + let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant(1))] } + + it do + expect(page).to have_css('.condition-error') + expect(page).to have_content("ne peut pas être utilisé") + end + end + + context 'when the types mismatch' do + let(:tdc) { create(:type_de_champ_integer_number) } + let(:upper_tdcs) { [tdc] } + let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant('a'))] } + + it { expect(page).to have_content("Il ne peut pas être") } + end + end +end From bf0f43f0ec86b5d4de1aa226809f95ed292a72ad Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Jul 2022 12:51:35 +0200 Subject: [PATCH 09/17] fix: component preview --- app/views/layouts/component_preview.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/component_preview.html.haml b/app/views/layouts/component_preview.html.haml index cc9cebe04..ada6600eb 100644 --- a/app/views/layouts/component_preview.html.haml +++ b/app/views/layouts/component_preview.html.haml @@ -13,7 +13,7 @@ = favicon_link_tag(image_url("#{FAVICON_32PX_SRC}"), type: "image/png", sizes: "32x32") = favicon_link_tag(image_url("#{FAVICON_96PX_SRC}"), type: "image/png", sizes: "96x96") - = javascript_packs_with_chunks_tag 'application', defer: true + = vite_javascript_tag 'application' = preload_link_tag(asset_url("Muli-Regular.woff2")) = preload_link_tag(asset_url("Muli-Bold.woff2")) From d9c3dfa9160bd9143b5529bae9f894ba3ee9c6be Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 4 Jul 2022 14:01:45 +0200 Subject: [PATCH 10/17] add component preview --- .../conditions_component_preview.rb | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 spec/components/previews/types_de_champ/conditions_component_preview.rb diff --git a/spec/components/previews/types_de_champ/conditions_component_preview.rb b/spec/components/previews/types_de_champ/conditions_component_preview.rb new file mode 100644 index 000000000..928023699 --- /dev/null +++ b/spec/components/previews/types_de_champ/conditions_component_preview.rb @@ -0,0 +1,50 @@ +class TypesDeChamp::ConditionsComponentPreview < ViewComponent::Preview + include Logic + + def with_empty_condition + tdc = TypeDeChamp.create(type_champ: :text, condition: empty_operator(empty, empty), libelle: 't') + upper_tdcs = [] + + render TypesDeChamp::ConditionsComponent.new( + tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: '1' + ) + end + + def with_conditions + surface = TypeDeChamp.create(type_champ: :integer_number, libelle: 'surface') + appartement = TypeDeChamp.create(type_champ: :yes_no, libelle: 'appartement') + type_appartement = TypeDeChamp.create(type_champ: :drop_down_list, libelle: 'type', drop_down_list_value: "T1\r\nT2\r\nT3") + upper_tdcs = [surface, appartement, type_appartement] + + condition = ds_and([ + greater_than_eq(champ_value(surface.stable_id), constant(50)), + ds_eq(champ_value(appartement.stable_id), constant(true)), + ds_eq(champ_value(type_appartement.stable_id), constant('T2')) + ]) + tdc = TypeDeChamp.create(type_champ: :integer_number, condition: condition, libelle: 'nb de piece') + + render TypesDeChamp::ConditionsComponent.new( + tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: '1' + ) + end + + def with_errors + surface = TypeDeChamp.create(type_champ: :integer_number, libelle: 'surface') + address = TypeDeChamp.create(type_champ: :address, libelle: 'adresse') + yes_non = TypeDeChamp.create(type_champ: :yes_no, libelle: 'oui/non') + + upper_tdcs = [address, yes_non] + + condition = ds_and([ + ds_eq(champ_value(address.stable_id), empty), + greater_than_eq(champ_value(surface.stable_id), constant(50)), + ds_eq(champ_value(yes_non.stable_id), constant(5)) + ]) + + tdc = TypeDeChamp.create(type_champ: :integer_number, condition: condition, libelle: 'nb de piece') + + render TypesDeChamp::ConditionsComponent.new( + tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: '1' + ) + end +end From 01bc7aa29e5fc6c0a2d4ce8061ae9d081acdb7e9 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 6 Jul 2022 17:19:04 +0200 Subject: [PATCH 11/17] make it world wide --- .../types_de_champ/conditions_component.rb | 38 +++++++++++-------- .../conditions_component.fr.yml | 9 +++++ .../conditions_errors_component.rb | 12 ++++-- .../conditions_errors_component.fr.yml | 6 +++ config/locales/models/logic/fr.yml | 3 ++ 5 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 app/components/types_de_champ/conditions_component/conditions_component.fr.yml diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index a9eaf4efc..025b0c263 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -22,28 +22,34 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent def logic_conditionnel_button if @condition.nil? - submit_tag('cliquer pour activer', formaction: add_row_admin_procedure_condition_path(@procedure_id, @tdc.id)) + submit_tag(t('.enable_conditionnel'), formaction: add_row_admin_procedure_condition_path(@procedure_id, @tdc.id)) else submit_tag( - 'cliquer pour désactiver', + t('.disable_conditionnel'), formmethod: 'delete', formnovalidate: true, - data: { confirm: "La logique conditionnelle appliquée à ce champ sera désactivé.\nVoulez-vous continuer ?" } + data: { confirm: t('.disable_conditionnel_alert') } ) end end def far_left_tag(row_number) if row_number == 0 - 'Afficher si' + t('.display_if') elsif row_number == 1 select_tag( "#{input_prefix}[top_operator_name]", - options_for_select([['Et', And.name], ['Ou', Or.name]], @condition.class.name) + options_for_select(options_for_far_left_tag, @condition.class.name) ) end end + def options_for_far_left_tag + [And, Or] + .map(&:name) + .map { |name| [t(name, scope: 'logic.operators'), name] } + end + def left_operand_tag(targeted_champ, row_index) current_target_valid = targets.map(&:second).include?(targeted_champ.to_json) @@ -60,7 +66,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent def targets available_targets - .then { |targets| targets.unshift(['Sélectionner', empty.to_json]) } + .then { |targets| targets.unshift([t('.select'), empty.to_json]) } end def available_targets @@ -75,7 +81,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent current_operator_valid = ops.map(&:second).include?(operator_name) if !current_operator_valid - ops.unshift(['Sélectionner', EmptyOperator.name]) + ops.unshift([t('.select'), EmptyOperator.name]) end select_tag( @@ -90,15 +96,15 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent case left.type when ChampValue::CHAMP_VALUE_TYPE.fetch(:boolean) [ - ['Est', Eq.name] + [t('is', scope: 'logic'), Eq.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:empty) [ - ['Est', EmptyOperator.name] + [t('is', scope: 'logic'), EmptyOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:enum) [ - ['Est', Eq.name] + [t('is', scope: 'logic'), Eq.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:number) [Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq] @@ -114,10 +120,10 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent case left.type when :boolean - options = [['Oui', constant(true).to_json], ['Non', constant(false).to_json]] + options = [[t('utils.yes'), constant(true).to_json], [t('utils.no'), constant(false).to_json]] if !right_valid - options.unshift(['Sélectionner', empty]) + options.unshift([t('.select'), empty]) end select_tag( @@ -129,14 +135,14 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent when :empty select_tag( input_name_for('value'), - options_for_select([['Sélectionner', empty.to_json]]), + options_for_select([[t('.select'), empty.to_json]]), id: input_id_for('value', row_index) ) when :enum options = left.options if !right_valid - options.unshift(['Sélectionner', empty]) + options.unshift([t('.select'), empty]) end select_tag( @@ -171,7 +177,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent def add_condition_tag tag.button( - tag.span('', class: 'icon add') + tag.span("Ajouter une condition"), + tag.span('', class: 'icon add') + tag.span(t('.add_condition')), formaction: add_row_admin_procedure_condition_path(@procedure_id, @tdc.id), formnovalidate: true, class: 'add-row' @@ -180,7 +186,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent def delete_condition_tag(row_index) tag.button( - tag.span('', class: 'icon delete') + tag.span('Supprimer la ligne', class: 'sr-only'), + tag.span('', class: 'icon delete') + tag.span(t('.remove_a_row'), class: 'sr-only'), formaction: delete_row_admin_procedure_condition_path(@procedure_id, @tdc.id, row_index: row_index), formmethod: 'delete', formnovalidate: true diff --git a/app/components/types_de_champ/conditions_component/conditions_component.fr.yml b/app/components/types_de_champ/conditions_component/conditions_component.fr.yml new file mode 100644 index 000000000..1593ff1f9 --- /dev/null +++ b/app/components/types_de_champ/conditions_component/conditions_component.fr.yml @@ -0,0 +1,9 @@ +--- +fr: + display_if: Afficher si + enable_conditionnel: cliquer pour activer + disable_conditionnel: cliquer pour désactiver + disable_conditionnel_alert: "La logique conditionnelle appliquée à ce champ sera désactivé.\nVoulez-vous continuer ?" + select: Sélectionner + add_condition: Ajouter une condition + remove_a_row: Supprimer la ligne diff --git a/app/components/types_de_champ/conditions_errors_component.rb b/app/components/types_de_champ/conditions_errors_component.rb index c9d706145..5fa205bb2 100644 --- a/app/components/types_de_champ/conditions_errors_component.rb +++ b/app/components/types_de_champ/conditions_errors_component.rb @@ -18,11 +18,17 @@ class TypesDeChamp::ConditionsErrorsComponent < ApplicationComponent targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == left.stable_id } if targeted_champ.nil? - "Un champ cible n'est plus disponible. Il est soit supprimé, soit déplacé en dessous de ce champ." + t('not_available', scope: '.errors') elsif left.type == :unmanaged - "Le champ « #{targeted_champ.libelle} » de type #{targeted_champ.type_champ} ne peut pas être utilisé comme champ cible." + t('unmanaged', scope: '.errors', + libelle: targeted_champ.libelle, + type_champ: t(targeted_champ.type_champ, scope: '.type')) else - "Le champ « #{targeted_champ.libelle} » est #{t(left.type, scope: '.type')}. Il ne peut pas être #{t(operator_name, scope: 'logic.operators').downcase} #{right.to_s.downcase}." + t('incompatible', scope: '.errors', + libelle: targeted_champ.libelle, + type_champ: t(targeted_champ.type_champ, scope: '.type'), + operator: t(operator_name, scope: 'logic.operators').downcase, + right: right.to_s.downcase) end end diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml index 213de5ed8..aecf81d2e 100644 --- a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml +++ b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml @@ -4,3 +4,9 @@ fr: number: un nombre string: un texte boolean: soit oui, soit non + yes_no: soit oui, soit non + address: une adresse + errors: + not_available: "Un champ cible n'est plus disponible. Il est soit supprimé, soit déplacé en dessous de ce champ." + unmanaged: "Le champ « %{libelle} » est %{type_champ} et ne peut pas être utilisé comme champ cible." + incompatible: "Le champ « %{libelle} » est %{type_champ}. Il ne peut pas être %{operator} %{right}." diff --git a/config/locales/models/logic/fr.yml b/config/locales/models/logic/fr.yml index 3f48dadd9..40eeb5f9f 100644 --- a/config/locales/models/logic/fr.yml +++ b/config/locales/models/logic/fr.yml @@ -1,9 +1,12 @@ fr: logic: empty: un membre vide + is: Est operators: 'Logic::LessThan': Inférieur à 'Logic::LessThanEq': Inférieur ou égal à 'Logic::Eq': Égal à 'Logic::GreaterThan': Supérieur à 'Logic::GreaterThanEq': Supérieur ou égal à + 'Logic::And': Et + 'Logic::Or': Ou From 62b5bd974ebcb1050ab8102883405cd997a81dab Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 6 Jul 2022 17:39:31 +0200 Subject: [PATCH 12/17] add comments --- app/components/types_de_champ/conditions_component.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 025b0c263..d5cdcf05e 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -51,7 +51,11 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def left_operand_tag(targeted_champ, row_index) - current_target_valid = targets.map(&:second).include?(targeted_champ.to_json) + # current_target can be invalid if + # - its type has changed : number -> carto + # - it has been removed + # - it has been put lower in the form + current_target_valid = targets_for_select.map(&:second).include?(targeted_champ.to_json) selected_target = current_target_valid ? targeted_champ.to_json : empty.to_json From dfd63d4f7564b18cfb2a13823cabd0cd499bc9d4 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 6 Jul 2022 17:39:38 +0200 Subject: [PATCH 13/17] renaming --- .../types_de_champ/conditions_component.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index d5cdcf05e..9168df1e8 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -61,42 +61,42 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent select_tag( input_name_for('targeted_champ'), - options_for_select(targets, selected_target), + options_for_select(targets_for_select, selected_target), onchange: "this.form.action = this.form.action + '/change_targeted_champ?row_index=#{row_index}'", id: input_id_for('targeted_champ', row_index), class: { alert: !current_target_valid } ) end - def targets - available_targets + def targets_for_select + available_targets_for_select .then { |targets| targets.unshift([t('.select'), empty.to_json]) } end - def available_targets + def available_targets_for_select @upper_tdcs .filter { |tdc| ChampValue::MANAGED_TYPE_DE_CHAMP.values.include?(tdc.type_champ) } .map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] } end def operator_tag(operator_name, targeted_champ, row_index) - ops = compatibles_operators(targeted_champ) + operators_for_select = compatibles_operators_for_select(targeted_champ) - current_operator_valid = ops.map(&:second).include?(operator_name) + current_operator_valid = operators_for_select.map(&:second).include?(operator_name) if !current_operator_valid - ops.unshift([t('.select'), EmptyOperator.name]) + operators_for_select.unshift([t('.select'), EmptyOperator.name]) end select_tag( input_name_for('operator_name'), - options_for_select(ops, selected: operator_name), + options_for_select(operators_for_select, selected: operator_name), id: input_id_for('operator_name', row_index), class: { alert: !current_operator_valid } ) end - def compatibles_operators(left) + def compatibles_operators_for_select(left) case left.type when ChampValue::CHAMP_VALUE_TYPE.fetch(:boolean) [ @@ -198,7 +198,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def render? - @condition.present? || available_targets.any? + @condition.present? || available_targets_for_select.any? end def input_name_for(name) From 3fc3bb6d54530f140e1497927cd3045dc2fec363 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 6 Jul 2022 20:26:34 +0200 Subject: [PATCH 14/17] simplify fargets_for_select --- app/components/types_de_champ/conditions_component.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 9168df1e8..54ec1620f 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -69,8 +69,11 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def targets_for_select - available_targets_for_select - .then { |targets| targets.unshift([t('.select'), empty.to_json]) } + empty_target_for_select + available_targets_for_select + end + + def empty_target_for_select + [[t('.select'), empty.to_json]] end def available_targets_for_select From 4ac66f2b99cf0031607310f1aa906e582ed1365a Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Jul 2022 10:38:14 +0200 Subject: [PATCH 15/17] simplify negation and alert --- .../types_de_champ/conditions_component.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 54ec1620f..22e0dbf91 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -85,17 +85,17 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent def operator_tag(operator_name, targeted_champ, row_index) operators_for_select = compatibles_operators_for_select(targeted_champ) - current_operator_valid = operators_for_select.map(&:second).include?(operator_name) + current_operator_invalid = !operators_for_select.map(&:second).include?(operator_name) - if !current_operator_valid - operators_for_select.unshift([t('.select'), EmptyOperator.name]) + if current_operator_invalid + operators_for_select = [[t('.select'), EmptyOperator.name]] + operators_for_select end select_tag( input_name_for('operator_name'), options_for_select(operators_for_select, selected: operator_name), id: input_id_for('operator_name', row_index), - class: { alert: !current_operator_valid } + class: { alert: current_operator_invalid } ) end @@ -123,13 +123,13 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent end def right_operand_tag(left, right, row_index) - right_valid = current_right_valid?(left, right) + right_invalid = !current_right_valid?(left, right) case left.type when :boolean options = [[t('utils.yes'), constant(true).to_json], [t('utils.no'), constant(false).to_json]] - if !right_valid + if right_invalid options.unshift([t('.select'), empty]) end @@ -137,7 +137,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent input_name_for('value'), options_for_select(options, right.to_json), id: input_id_for('value', row_index), - class: right_valid ? nil : 'alert' + class: { alert: right_invalid } ) when :empty select_tag( @@ -148,7 +148,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent when :enum options = left.options - if !right_valid + if right_invalid options.unshift([t('.select'), empty]) end @@ -156,7 +156,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent input_name_for('value'), options_for_select(options, right.value), id: input_id_for('value', row_index), - class: right_valid ? nil : 'alert' + class: { alert: right_invalid } ) when :number number_field_tag( @@ -164,7 +164,7 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent right.value, required: true, id: input_id_for('value', row_index), - class: right_valid ? nil : 'alert' + class: { alert: right_invalid } ) else number_field_tag(input_name_for('value'), '', id: input_id_for('value', row_index)) From 5ea88422940e8db14e1d0e1aaade4398d9a83ffc Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Jul 2022 10:46:38 +0200 Subject: [PATCH 16/17] more renaming --- .../types_de_champ/conditions_component.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ/conditions_component.rb index 22e0dbf91..fff4ad938 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ/conditions_component.rb @@ -127,34 +127,34 @@ class TypesDeChamp::ConditionsComponent < ApplicationComponent case left.type when :boolean - options = [[t('utils.yes'), constant(true).to_json], [t('utils.no'), constant(false).to_json]] + booleans_for_select = [[t('utils.yes'), constant(true).to_json], [t('utils.no'), constant(false).to_json]] if right_invalid - options.unshift([t('.select'), empty]) + booleans_for_select = empty_target_for_select + booleans_for_select end select_tag( input_name_for('value'), - options_for_select(options, right.to_json), + options_for_select(booleans_for_select, right.to_json), id: input_id_for('value', row_index), class: { alert: right_invalid } ) when :empty select_tag( input_name_for('value'), - options_for_select([[t('.select'), empty.to_json]]), + options_for_select(empty_target_for_select), id: input_id_for('value', row_index) ) when :enum - options = left.options + enums_for_select = left.options if right_invalid - options.unshift([t('.select'), empty]) + enums_for_select = empty_target_for_select + enums_for_select end select_tag( input_name_for('value'), - options_for_select(options, right.value), + options_for_select(enums_for_select, right.value), id: input_id_for('value', row_index), class: { alert: right_invalid } ) From 0ffa23c2597f6f0b876d20c8e786e5782915fd13 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 7 Jul 2022 11:18:47 +0200 Subject: [PATCH 17/17] move under types_de_champ_editor namespace --- .../conditions_component.rb | 2 +- .../conditions_component/conditions_component.fr.yml | 0 .../conditions_component/conditions_component.html.haml | 2 +- .../conditions_errors_component.rb | 2 +- .../conditions_errors_component.fr.yml | 0 .../conditions_errors_component.html.haml | 0 .../conditions_component_preview.rb | 8 ++++---- .../conditions_component_spec.rb | 2 +- .../conditions_errors_component_spec.rb | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) rename app/components/{types_de_champ => types_de_champ_editor}/conditions_component.rb (98%) rename app/components/{types_de_champ => types_de_champ_editor}/conditions_component/conditions_component.fr.yml (100%) rename app/components/{types_de_champ => types_de_champ_editor}/conditions_component/conditions_component.html.haml (90%) rename app/components/{types_de_champ => types_de_champ_editor}/conditions_errors_component.rb (94%) rename app/components/{types_de_champ => types_de_champ_editor}/conditions_errors_component/conditions_errors_component.fr.yml (100%) rename app/components/{types_de_champ => types_de_champ_editor}/conditions_errors_component/conditions_errors_component.html.haml (100%) rename spec/components/previews/{types_de_champ => types_de_champ_editor}/conditions_component_preview.rb (87%) rename spec/components/{types_de_champ => types_de_champ_editor}/conditions_component_spec.rb (98%) rename spec/components/{types_de_champ => types_de_champ_editor}/conditions_errors_component_spec.rb (94%) diff --git a/app/components/types_de_champ/conditions_component.rb b/app/components/types_de_champ_editor/conditions_component.rb similarity index 98% rename from app/components/types_de_champ/conditions_component.rb rename to app/components/types_de_champ_editor/conditions_component.rb index fff4ad938..3a68ee59b 100644 --- a/app/components/types_de_champ/conditions_component.rb +++ b/app/components/types_de_champ_editor/conditions_component.rb @@ -1,4 +1,4 @@ -class TypesDeChamp::ConditionsComponent < ApplicationComponent +class TypesDeChampEditor::ConditionsComponent < ApplicationComponent include Logic def initialize(tdc:, upper_tdcs:, procedure_id:) diff --git a/app/components/types_de_champ/conditions_component/conditions_component.fr.yml b/app/components/types_de_champ_editor/conditions_component/conditions_component.fr.yml similarity index 100% rename from app/components/types_de_champ/conditions_component/conditions_component.fr.yml rename to app/components/types_de_champ_editor/conditions_component/conditions_component.fr.yml diff --git a/app/components/types_de_champ/conditions_component/conditions_component.html.haml b/app/components/types_de_champ_editor/conditions_component/conditions_component.html.haml similarity index 90% rename from app/components/types_de_champ/conditions_component/conditions_component.html.haml rename to app/components/types_de_champ_editor/conditions_component/conditions_component.html.haml index 871cb2e9b..2cccb45b5 100644 --- a/app/components/types_de_champ/conditions_component/conditions_component.html.haml +++ b/app/components/types_de_champ_editor/conditions_component/conditions_component.html.haml @@ -5,7 +5,7 @@ %p.mr-2 Logique conditionnelle = logic_conditionnel_button - = render TypesDeChamp::ConditionsErrorsComponent.new(conditions: condition_per_row, upper_tdcs: @upper_tdcs) + = render TypesDeChampEditor::ConditionsErrorsComponent.new(conditions: condition_per_row, upper_tdcs: @upper_tdcs) - if @condition.present? %table.condition-table.mt-2.width-100 diff --git a/app/components/types_de_champ/conditions_errors_component.rb b/app/components/types_de_champ_editor/conditions_errors_component.rb similarity index 94% rename from app/components/types_de_champ/conditions_errors_component.rb rename to app/components/types_de_champ_editor/conditions_errors_component.rb index 5fa205bb2..fd7263274 100644 --- a/app/components/types_de_champ/conditions_errors_component.rb +++ b/app/components/types_de_champ_editor/conditions_errors_component.rb @@ -1,4 +1,4 @@ -class TypesDeChamp::ConditionsErrorsComponent < ApplicationComponent +class TypesDeChampEditor::ConditionsErrorsComponent < ApplicationComponent def initialize(conditions:, upper_tdcs:) @conditions, @upper_tdcs = conditions, upper_tdcs end diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml b/app/components/types_de_champ_editor/conditions_errors_component/conditions_errors_component.fr.yml similarity index 100% rename from app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml rename to app/components/types_de_champ_editor/conditions_errors_component/conditions_errors_component.fr.yml diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml b/app/components/types_de_champ_editor/conditions_errors_component/conditions_errors_component.html.haml similarity index 100% rename from app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml rename to app/components/types_de_champ_editor/conditions_errors_component/conditions_errors_component.html.haml diff --git a/spec/components/previews/types_de_champ/conditions_component_preview.rb b/spec/components/previews/types_de_champ_editor/conditions_component_preview.rb similarity index 87% rename from spec/components/previews/types_de_champ/conditions_component_preview.rb rename to spec/components/previews/types_de_champ_editor/conditions_component_preview.rb index 928023699..3edab6544 100644 --- a/spec/components/previews/types_de_champ/conditions_component_preview.rb +++ b/spec/components/previews/types_de_champ_editor/conditions_component_preview.rb @@ -1,11 +1,11 @@ -class TypesDeChamp::ConditionsComponentPreview < ViewComponent::Preview +class TypesDeChampEditor::ConditionsComponentPreview < ViewComponent::Preview include Logic def with_empty_condition tdc = TypeDeChamp.create(type_champ: :text, condition: empty_operator(empty, empty), libelle: 't') upper_tdcs = [] - render TypesDeChamp::ConditionsComponent.new( + render TypesDeChampEditor::ConditionsComponent.new( tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: '1' ) end @@ -23,7 +23,7 @@ class TypesDeChamp::ConditionsComponentPreview < ViewComponent::Preview ]) tdc = TypeDeChamp.create(type_champ: :integer_number, condition: condition, libelle: 'nb de piece') - render TypesDeChamp::ConditionsComponent.new( + render TypesDeChampEditor::ConditionsComponent.new( tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: '1' ) end @@ -43,7 +43,7 @@ class TypesDeChamp::ConditionsComponentPreview < ViewComponent::Preview tdc = TypeDeChamp.create(type_champ: :integer_number, condition: condition, libelle: 'nb de piece') - render TypesDeChamp::ConditionsComponent.new( + render TypesDeChampEditor::ConditionsComponent.new( tdc: tdc, upper_tdcs: upper_tdcs, procedure_id: '1' ) end diff --git a/spec/components/types_de_champ/conditions_component_spec.rb b/spec/components/types_de_champ_editor/conditions_component_spec.rb similarity index 98% rename from spec/components/types_de_champ/conditions_component_spec.rb rename to spec/components/types_de_champ_editor/conditions_component_spec.rb index d93c3a7c6..e4831f87b 100644 --- a/spec/components/types_de_champ/conditions_component_spec.rb +++ b/spec/components/types_de_champ_editor/conditions_component_spec.rb @@ -1,4 +1,4 @@ -describe TypesDeChamp::ConditionsComponent, type: :component do +describe TypesDeChampEditor::ConditionsComponent, type: :component do include Logic describe 'render' do diff --git a/spec/components/types_de_champ/conditions_errors_component_spec.rb b/spec/components/types_de_champ_editor/conditions_errors_component_spec.rb similarity index 94% rename from spec/components/types_de_champ/conditions_errors_component_spec.rb rename to spec/components/types_de_champ_editor/conditions_errors_component_spec.rb index 4a9bc8532..74ea2d8f5 100644 --- a/spec/components/types_de_champ/conditions_errors_component_spec.rb +++ b/spec/components/types_de_champ_editor/conditions_errors_component_spec.rb @@ -1,4 +1,4 @@ -describe TypesDeChamp::ConditionsErrorsComponent, type: :component do +describe TypesDeChampEditor::ConditionsErrorsComponent, type: :component do include Logic describe 'render' do