Merge pull request #7532 from betagouv/champs-placeholders
feat: Champs with realistic placeholders
This commit is contained in:
commit
9f3a2a513f
23 changed files with 173 additions and 19 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -27,6 +27,7 @@ yarn-debug.log*
|
|||
/.vscode
|
||||
/.idea
|
||||
/public/assets
|
||||
/spec/support/spec_config.local.rb
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
|
14
README.md
14
README.md
|
@ -27,9 +27,21 @@ Vous souhaitez y apporter des changements ou des améliorations ? Lisez notre [
|
|||
|
||||
- Chrome
|
||||
- chromedriver :
|
||||
* Mac : `brew cask install chromedriver`
|
||||
* Mac : `brew install chromedriver`
|
||||
* Linux : voir https://sites.google.com/a/chromium.org/chromedriver/downloads
|
||||
|
||||
Si l'emplacement d'installation de Chrome n'est pas standard, ou que vous utilisez Brave ou Chromium à la place,
|
||||
il peut être nécessaire d'overrider pour votre machine le path vers le binaire Chrome, par exemple :
|
||||
|
||||
```ruby
|
||||
# create file spec/support/spec_config.local.rb
|
||||
|
||||
Selenium::WebDriver::Chrome.path = "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
|
||||
|
||||
# Must exactly match the browser version
|
||||
Webdrivers::Chromedriver.required_version = "103.0.5060.53"
|
||||
```
|
||||
|
||||
### Création des rôles de la base de données
|
||||
|
||||
Les informations nécessaire à l'initialisation de la base doivent être pré-configurées à la main grâce à la procédure suivante :
|
||||
|
|
|
@ -565,12 +565,13 @@
|
|||
}
|
||||
|
||||
.fconnect-form {
|
||||
input[type=password] {
|
||||
input[type='password'] {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
opacity: 0.6; // normalize opacity across browsers
|
||||
color: $dark-grey;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)
|
||||
= form.text_area :description, class: 'small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :description)
|
||||
|
||||
- if type_de_champ.generic?
|
||||
.cell.mt-1
|
||||
= form.label :placeholder, t(".generic.custom_placeholder_title"), class: 'flex-grow', for: dom_id(type_de_champ, :placeholder)
|
||||
= form.text_field :placeholder, class: 'small-margin small width-100', placeholder: t("#{type_de_champ.type_champ}.placeholder", scope: "shared.dossiers.editable_champs"), id: dom_id(type_de_champ, :placeholder)
|
||||
%p
|
||||
= t(".generic.custom_placeholder_hint")
|
||||
|
||||
.flex.justify-start.mt-1
|
||||
- if type_de_champ.drop_down_list?
|
||||
.flex.column.justify-start.width-33
|
||||
|
|
|
@ -68,6 +68,7 @@ module Administrateurs
|
|||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:piece_justificative_template,
|
||||
:placeholder,
|
||||
editable_options: [
|
||||
:cadastres,
|
||||
:unesco,
|
||||
|
|
|
@ -379,6 +379,18 @@ class ProcedureRevision < ApplicationRecord
|
|||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if from_type_de_champ.placeholder != to_type_de_champ.placeholder
|
||||
changes << {
|
||||
model: :type_de_champ,
|
||||
op: :update,
|
||||
attribute: :placeholder,
|
||||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.placeholder,
|
||||
to: to_type_de_champ.placeholder,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if to_type_de_champ.drop_down_list?
|
||||
if from_type_de_champ.drop_down_list_options != to_type_de_champ.drop_down_list_options
|
||||
changes << {
|
||||
|
|
|
@ -58,7 +58,16 @@ class TypeDeChamp < ApplicationRecord
|
|||
mesri: 'mesri'
|
||||
}
|
||||
|
||||
store_accessor :options, :cadastres, :old_pj, :drop_down_options, :skip_pj_validation, :skip_content_type_pj_validation, :drop_down_secondary_libelle, :drop_down_secondary_description, :drop_down_other
|
||||
store_accessor :options, :cadastres,
|
||||
:drop_down_options,
|
||||
:drop_down_other,
|
||||
:drop_down_secondary_description,
|
||||
:drop_down_secondary_libelle,
|
||||
:old_pj,
|
||||
:placeholder,
|
||||
:skip_content_type_pj_validation,
|
||||
:skip_pj_validation
|
||||
|
||||
has_many :revision_types_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', dependent: :destroy, inverse_of: :type_de_champ
|
||||
has_one :revision_type_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', inverse_of: false
|
||||
has_many :revisions, -> { ordered }, through: :revision_types_de_champ
|
||||
|
@ -217,6 +226,10 @@ class TypeDeChamp < ApplicationRecord
|
|||
type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
||||
end
|
||||
|
||||
def generic?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:text) || type_champ == TypeDeChamp.type_champs.fetch(:textarea)
|
||||
end
|
||||
|
||||
def exclude_from_view?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:explication)
|
||||
end
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
%li.mb-1= t("administrateurs.revision_changes.update_drop_down_other#{postfix}.enabled", label: change[:label])
|
||||
- else
|
||||
%li.mb-1= t("administrateurs.revision_changes.update_drop_down_other#{postfix}.disabled", label: change[:label])
|
||||
- when :placeholder
|
||||
%li.mb-1= t("update_placeholder#{postfix}", label: change[:label], to: change[:to], scope: [:administrateurs, :revision_changes])
|
||||
- when :carte_layers
|
||||
- added = change[:to].sort - change[:from].sort
|
||||
- removed = change[:from].sort - change[:to].sort
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
= form.email_field :value,
|
||||
id: champ.input_id,
|
||||
aria: { describedby: champ.describedby_id },
|
||||
placeholder: champ.libelle,
|
||||
placeholder: t(".placeholder"),
|
||||
required: champ.mandatory?
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
= form.text_field :value,
|
||||
id: champ.input_id,
|
||||
placeholder: "27 caractères au format FR7630006000011234567890189",
|
||||
placeholder: t(".placeholder"),
|
||||
required: champ.mandatory?,
|
||||
aria: { describedby: champ.describedby_id },
|
||||
data: { controller: 'iban-input'}
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
= form.phone_field :value,
|
||||
id: champ.input_id,
|
||||
aria: { describedby: champ.describedby_id },
|
||||
placeholder: champ.libelle,
|
||||
placeholder: t(".placeholder"),
|
||||
required: champ.mandatory?,
|
||||
pattern: "[^a-z^A-Z]+"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
= form.text_field :value,
|
||||
id: champ.input_id,
|
||||
aria: { describedby: champ.describedby_id },
|
||||
placeholder: champ.libelle,
|
||||
placeholder: t(".placeholder"),
|
||||
data: { controller: 'turbo-input', turbo_input_url_value: champs_siret_path(champ.id) },
|
||||
required: champ.mandatory?,
|
||||
pattern: "[0-9]{14}",
|
||||
title: "Le numéro de SIRET doit comporter exactement 14 chiffres"
|
||||
title: t(".title")
|
||||
.spinner.right.hidden
|
||||
.siret-info{ id: dom_id(champ, :siret_info) }
|
||||
- if champ.etablissement.present?
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
= form.text_field :value,
|
||||
id: champ.input_id,
|
||||
placeholder: champ.libelle,
|
||||
placeholder: champ.type_de_champ.placeholder.presence || t(".placeholder"),
|
||||
required: champ.mandatory?,
|
||||
aria: { describedby: champ.describedby_id }
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
aria: { describedby: champ.describedby_id },
|
||||
rows: 6,
|
||||
required: champ.mandatory?,
|
||||
value: html_to_string(champ.value)
|
||||
value: html_to_string(champ.value),
|
||||
placeholder: champ.type_de_champ.placeholder.presence || t(".placeholder")
|
||||
|
|
|
@ -575,3 +575,9 @@ fr:
|
|||
weekly_distribution_details: "au cours des 6 derniers mois"
|
||||
procedure_description:
|
||||
estimated_fill_duration: "Temps de remplissage estimé : %{estimated_minutes} mn"
|
||||
|
||||
types_de_champ_editor:
|
||||
champ_component:
|
||||
generic:
|
||||
custom_placeholder_title: "Spécimen de saisie (optionnel)"
|
||||
custom_placeholder_hint: Modèle de réponse visible dans le champ avant la saisie par l'usager
|
||||
|
|
|
@ -12,12 +12,25 @@ en:
|
|||
numero_fiscal_notice: It is usually composed of 13 to 14 characters.
|
||||
reference_avis_label: Tax notice reference
|
||||
reference_avis_notice: It is usually composed of 13 to 14 characters.
|
||||
pole_emploi:
|
||||
identifiant_label: Identifier
|
||||
identifiant_notice: It is usually composed of alphanumeric characters.
|
||||
email:
|
||||
placeholder: "camilya.martin@exemple.fr"
|
||||
iban:
|
||||
placeholder: "FR76 3000 6000 0012 3456 7890 189"
|
||||
mesri:
|
||||
ine_label: INE
|
||||
ine_notice: Student National Number. It is usually composed of alphanumeric characters.
|
||||
phone:
|
||||
placeholder: "0612345678"
|
||||
pole_emploi:
|
||||
identifiant_label: Identifier
|
||||
identifiant_notice: It is usually composed of alphanumeric characters.
|
||||
siret:
|
||||
placeholder: "50000123456789"
|
||||
title: "The SIRET number must have exactly 14 digits"
|
||||
text:
|
||||
placeholder: "Your answer"
|
||||
textarea:
|
||||
placeholder: "Write your answer here"
|
||||
header:
|
||||
expires_at:
|
||||
brouillon: "Expires on %{date} (%{duree_conservation_totale} months after this file was created)"
|
||||
|
|
|
@ -12,12 +12,25 @@ fr:
|
|||
numero_fiscal_notice: Il est généralement composé de 13 ou 14 caractères.
|
||||
reference_avis_label: La référence d'avis d'imposition
|
||||
reference_avis_notice: Elle est généralement composée de 13 ou 14 caractères.
|
||||
pole_emploi:
|
||||
identifiant_label: Identifiant
|
||||
identifiant_notice: Il est généralement composé de caractères alphanumériques.
|
||||
email:
|
||||
placeholder: "camilya.martin@exemple.fr"
|
||||
iban:
|
||||
placeholder: "FR76 3000 6000 0012 3456 7890 189"
|
||||
mesri:
|
||||
ine_label: INE
|
||||
ine_notice: Identifiant National Étudiant. Il est généralement composé de caractères alphanumériques.
|
||||
phone:
|
||||
placeholder: "0612345678"
|
||||
pole_emploi:
|
||||
identifiant_label: Identifiant
|
||||
identifiant_notice: Il est généralement composé de caractères alphanumériques.
|
||||
siret:
|
||||
placeholder: "50000123456789"
|
||||
title: "Le numéro de SIRET doit comporter exactement 14 chiffres"
|
||||
text:
|
||||
placeholder: "Votre réponse"
|
||||
textarea:
|
||||
placeholder: "Rédigez ici votre réponse"
|
||||
header:
|
||||
expires_at:
|
||||
brouillon: "Expirera le %{date} (%{duree_conservation_totale} mois après la création du dossier)"
|
||||
|
|
|
@ -28,6 +28,7 @@ fr:
|
|||
enabled: Le champ « %{label} » comporte maintenant un choix « Autre »
|
||||
disabled: Le champ « %{label} » ne comporte plus de choix « Autre »
|
||||
update_carte_layers: Les référentiels cartographiques du champ « %{label} » ont été modifiés
|
||||
update_placeholder: Le spécimen de saisie du champ « %{label} » a été modifié. Le nouveau spécimen est « %{to} ».
|
||||
add_private: L’annotation privée « %{label} » a été ajoutée
|
||||
remove_private: L’annotation privée « %{label} » a été supprimée
|
||||
move_private:
|
||||
|
|
|
@ -18,7 +18,8 @@ describe Administrateurs::TypesDeChampController, type: :controller do
|
|||
type_de_champ: {
|
||||
type_champ: type_champ,
|
||||
libelle: 'Nouveau champ',
|
||||
private: false
|
||||
private: false,
|
||||
placeholder: "custom placeholder"
|
||||
}
|
||||
}, format: :turbo_stream
|
||||
end
|
||||
|
|
|
@ -329,7 +329,7 @@ describe ProcedureRevision do
|
|||
before do
|
||||
updated_tdc = new_draft.find_and_ensure_exclusive_use(first_tdc.stable_id)
|
||||
|
||||
updated_tdc.update(libelle: 'modifier le libelle', description: 'une description', mandatory: !updated_tdc.mandatory)
|
||||
updated_tdc.update(libelle: 'modifier le libelle', description: 'une description', mandatory: !updated_tdc.mandatory, placeholder: "new placeholder")
|
||||
end
|
||||
|
||||
it do
|
||||
|
@ -363,6 +363,16 @@ describe ProcedureRevision do
|
|||
from: false,
|
||||
to: true,
|
||||
stable_id: first_tdc.stable_id
|
||||
},
|
||||
{
|
||||
model: :type_de_champ,
|
||||
op: :update,
|
||||
attribute: :placeholder,
|
||||
label: first_tdc.libelle,
|
||||
private: false,
|
||||
from: first_tdc.placeholder,
|
||||
to: "new placeholder",
|
||||
stable_id: first_tdc.stable_id
|
||||
}
|
||||
])
|
||||
end
|
||||
|
|
|
@ -165,4 +165,35 @@ describe 'As an administrateur I can edit types de champ', js: true do
|
|||
end
|
||||
expect(page).not_to have_content('Durée de remplissage estimée')
|
||||
end
|
||||
|
||||
describe "placeholders for generic types" do
|
||||
let(:placeholder) { "my placeholder" }
|
||||
before do
|
||||
add_champ
|
||||
end
|
||||
|
||||
it "text champ" do
|
||||
select('Texte', from: 'Type de champ')
|
||||
expect(page).to have_content('Spécimen de saisie')
|
||||
|
||||
fill_in 'Spécimen de saisie', with: placeholder
|
||||
|
||||
wait_until { procedure.draft_types_de_champ.first.placeholder == placeholder }
|
||||
|
||||
page.refresh
|
||||
expect(page).to have_selector("input[value='#{placeholder}']")
|
||||
end
|
||||
|
||||
it "textarea champ" do
|
||||
select('Zone de texte', from: 'Type de champ')
|
||||
expect(page).to have_content('Spécimen de saisie')
|
||||
|
||||
fill_in 'Spécimen de saisie', with: placeholder
|
||||
|
||||
wait_until { procedure.draft_types_de_champ.first.placeholder == placeholder }
|
||||
|
||||
page.refresh
|
||||
expect(page).to have_selector("input[value='#{placeholder}']")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ describe 'The user' do
|
|||
fill_individual
|
||||
|
||||
# fill data
|
||||
fill_in('text', with: 'super texte')
|
||||
fill_in('text *', with: 'super texte')
|
||||
fill_in('textarea', with: 'super textarea')
|
||||
fill_in('date', with: '12-12-2012')
|
||||
select_date_and_time(Time.zone.parse('06/01/2030 7h05'), form_id_for_datetime('datetime'))
|
||||
|
|
|
@ -23,6 +23,35 @@ describe 'shared/dossiers/edit.html.haml', type: :view do
|
|||
expect(subject).to have_field(champ_dossier_link.libelle, with: champ_dossier_link.value)
|
||||
expect(subject).to have_field(champ_textarea.libelle, with: champ_textarea.value)
|
||||
end
|
||||
|
||||
context "with standard champs" do
|
||||
let(:champ_email) { create(:champ_email, dossier: dossier) }
|
||||
let(:champ_phone) { create(:champ_phone, dossier: dossier) }
|
||||
let(:champs) { [champ_email, champ_phone] }
|
||||
|
||||
it "renders basic placeholders" do
|
||||
expect(subject).to have_css('input[type="email"][placeholder$="exemple.fr"]')
|
||||
expect(subject).to have_css('input[type="tel"][placeholder^="0612"]')
|
||||
end
|
||||
end
|
||||
|
||||
context "with generic champs" do
|
||||
let(:champ_text) { create(:champ_text, dossier: dossier) }
|
||||
let(:champs) { [champ_text, champ_textarea] }
|
||||
|
||||
it "renders default placeholders" do
|
||||
expect(subject).to have_css('input[placeholder*="réponse"]')
|
||||
expect(subject).to have_css('textarea[placeholder*="réponse"]')
|
||||
end
|
||||
|
||||
it "renders customized placeholders" do
|
||||
champ_text.type_de_champ.placeholder = "custom1 placeholder"
|
||||
champ_textarea.type_de_champ.placeholder = "custom2 placeholder"
|
||||
|
||||
expect(subject).to have_css('input[placeholder*="custom1"]')
|
||||
expect(subject).to have_css('textarea[placeholder*="custom2"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a single-value list' do
|
||||
|
|
Loading…
Reference in a new issue