fix(combobox): can copy past multiple values in restricted multi select combobox
This commit is contained in:
parent
e35584811c
commit
fb07a0ca54
5 changed files with 43 additions and 24 deletions
|
@ -17,6 +17,7 @@ class EditableChamp::MultipleDropDownListComponent < EditableChamp::EditableCham
|
||||||
name: @form.field_name(:value, multiple: true),
|
name: @form.field_name(:value, multiple: true),
|
||||||
selected_keys: @champ.selected_options,
|
selected_keys: @champ.selected_options,
|
||||||
items: @champ.enabled_non_empty_options,
|
items: @champ.enabled_non_empty_options,
|
||||||
|
value_separator: false,
|
||||||
'aria-label': @champ.libelle,
|
'aria-label': @champ.libelle,
|
||||||
'aria-describedby': @champ.describedby_id,
|
'aria-describedby': @champ.describedby_id,
|
||||||
'aria-labelledby': @champ.labelledby_id)
|
'aria-labelledby': @champ.labelledby_id)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
= form_tag update_displayed_fields_instructeur_procedure_path(@procedure), method: :patch, class: 'dropdown-form large columns-form' do
|
= form_tag update_displayed_fields_instructeur_procedure_path(@procedure), method: :patch, class: 'dropdown-form large columns-form' do
|
||||||
%react-fragment
|
%react-fragment
|
||||||
= render ReactComponent.new "ComboBox/MultiComboBox", items: @displayable_columns_for_select, selected_keys: @displayable_columns_selected, name: 'values[]', 'aria-label': 'Colonne à afficher'
|
= render ReactComponent.new "ComboBox/MultiComboBox", items: @displayable_columns_for_select, selected_keys: @displayable_columns_selected, name: 'values[]', 'aria-label': 'Colonne à afficher', value_separator: false
|
||||||
|
|
||||||
= submit_tag t('.save'), class: 'fr-btn fr-btn--secondary'
|
= submit_tag t('.save'), class: 'fr-btn fr-btn--secondary'
|
||||||
|
|
|
@ -168,13 +168,18 @@ export function useMultiList({
|
||||||
defaultItems?: Item[];
|
defaultItems?: Item[];
|
||||||
defaultSelectedKeys?: string[];
|
defaultSelectedKeys?: string[];
|
||||||
allowsCustomValue?: boolean;
|
allowsCustomValue?: boolean;
|
||||||
valueSeparator?: string;
|
valueSeparator?: string | false;
|
||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
focusInput?: () => void;
|
focusInput?: () => void;
|
||||||
formValue?: 'text' | 'key';
|
formValue?: 'text' | 'key';
|
||||||
}) {
|
}) {
|
||||||
const valueSeparatorRegExp = useMemo(
|
const valueSeparatorRegExp = useMemo(
|
||||||
() => (valueSeparator ? new RegExp(valueSeparator) : /\s|,|;/),
|
() =>
|
||||||
|
valueSeparator === false
|
||||||
|
? false
|
||||||
|
: valueSeparator
|
||||||
|
? new RegExp(valueSeparator)
|
||||||
|
: /\s|,|;/,
|
||||||
[valueSeparator]
|
[valueSeparator]
|
||||||
);
|
);
|
||||||
const [selectedKeys, setSelectedKeys] = useState(
|
const [selectedKeys, setSelectedKeys] = useState(
|
||||||
|
@ -219,7 +224,7 @@ export function useMultiList({
|
||||||
const values = selectedItems.map((item) =>
|
const values = selectedItems.map((item) =>
|
||||||
formValue == 'text' || allowsCustomValue ? item.label : item.value
|
formValue == 'text' || allowsCustomValue ? item.label : item.value
|
||||||
);
|
);
|
||||||
if (!allowsCustomValue || inputValue == '') {
|
if (!valueSeparatorRegExp || !allowsCustomValue || inputValue == '') {
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
|
@ -269,26 +274,34 @@ export function useMultiList({
|
||||||
setInputValue('');
|
setInputValue('');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (allowsCustomValue) {
|
|
||||||
const values = value.split(valueSeparatorRegExp);
|
if (!valueSeparatorRegExp) {
|
||||||
// if input contains a separator, add all values
|
|
||||||
if (values.length > 1) {
|
|
||||||
const addedKeys = values.filter(Boolean);
|
|
||||||
setSelectedKeys((keys) => {
|
|
||||||
const selectedKeys = new Set(keys.values());
|
|
||||||
for (const key of addedKeys) {
|
|
||||||
selectedKeys.add(key);
|
|
||||||
}
|
|
||||||
return selectedKeys;
|
|
||||||
});
|
|
||||||
setInputValue('');
|
|
||||||
} else {
|
|
||||||
setInputValue(value);
|
|
||||||
}
|
|
||||||
onChange?.();
|
|
||||||
} else {
|
|
||||||
setInputValue(value);
|
setInputValue(value);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const values = value.split(valueSeparatorRegExp);
|
||||||
|
if (values.length < 2) {
|
||||||
|
setInputValue(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if input contains a separator, add all values
|
||||||
|
const addedKeys = allowsCustomValue
|
||||||
|
? values.filter(Boolean)
|
||||||
|
: values
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((value) => items.find((item) => item.label == value)?.value)
|
||||||
|
.filter((key) => key != null);
|
||||||
|
setSelectedKeys((keys) => {
|
||||||
|
const selectedKeys = new Set(keys.values());
|
||||||
|
for (const key of addedKeys) {
|
||||||
|
selectedKeys.add(key);
|
||||||
|
}
|
||||||
|
return selectedKeys;
|
||||||
|
});
|
||||||
|
onChange?.();
|
||||||
|
setInputValue('');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ export const MultiComboBoxProps = s.assign(
|
||||||
s.object({
|
s.object({
|
||||||
selectedKeys: s.array(s.string()),
|
selectedKeys: s.array(s.string()),
|
||||||
allowsCustomValue: s.boolean(),
|
allowsCustomValue: s.boolean(),
|
||||||
valueSeparator: s.string()
|
valueSeparator: s.union([s.string(), s.literal(false)])
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,6 +7,8 @@ describe 'Inviting an expert:', js: true do
|
||||||
let(:instructeur) { create(:instructeur, password: SECURE_PASSWORD) }
|
let(:instructeur) { create(:instructeur, password: SECURE_PASSWORD) }
|
||||||
let(:expert) { create(:expert, password: expert_password) }
|
let(:expert) { create(:expert, password: expert_password) }
|
||||||
let(:expert2) { create(:expert, password: expert_password) }
|
let(:expert2) { create(:expert, password: expert_password) }
|
||||||
|
let(:expert3) { create(:expert, password: expert_password) }
|
||||||
|
let(:expert4) { create(:expert, password: expert_password) }
|
||||||
let(:expert_password) { 'mot de passe d’expert' }
|
let(:expert_password) { 'mot de passe d’expert' }
|
||||||
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur], types_de_champ_public: [{ type: :dossier_link }]) }
|
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur], types_de_champ_public: [{ type: :dossier_link }]) }
|
||||||
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
|
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
|
||||||
|
@ -31,6 +33,7 @@ describe 'Inviting an expert:', js: true do
|
||||||
within('.fr-sidemenu') { click_on 'Demander un avis' }
|
within('.fr-sidemenu') { click_on 'Demander un avis' }
|
||||||
expect(page).to have_current_path(avis_new_instructeur_dossier_path(procedure, dossier))
|
expect(page).to have_current_path(avis_new_instructeur_dossier_path(procedure, dossier))
|
||||||
|
|
||||||
|
fill_in 'Emails', with: "#{expert3.email},#{expert4.email}"
|
||||||
fill_in 'Emails', with: "#{expert.email},"
|
fill_in 'Emails', with: "#{expert.email},"
|
||||||
fill_in 'Emails', with: expert2.email
|
fill_in 'Emails', with: expert2.email
|
||||||
fill_in 'avis_introduction', with: 'Bonjour, merci de me donner votre avis sur ce dossier.'
|
fill_in 'avis_introduction', with: 'Bonjour, merci de me donner votre avis sur ce dossier.'
|
||||||
|
@ -45,10 +48,12 @@ describe 'Inviting an expert:', js: true do
|
||||||
within('section') do
|
within('section') do
|
||||||
expect(page).to have_content(expert.email.to_s)
|
expect(page).to have_content(expert.email.to_s)
|
||||||
expect(page).to have_content(expert2.email.to_s)
|
expect(page).to have_content(expert2.email.to_s)
|
||||||
|
expect(page).to have_content(expert3.email.to_s)
|
||||||
|
expect(page).to have_content(expert4.email.to_s)
|
||||||
expect(page).to have_content('Bonjour, merci de me donner votre avis sur ce dossier.')
|
expect(page).to have_content('Bonjour, merci de me donner votre avis sur ce dossier.')
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(Avis.count).to eq(4)
|
expect(Avis.count).to eq(8)
|
||||||
expect(emails_sent_to(expert.email.to_s).size).to eq(1)
|
expect(emails_sent_to(expert.email.to_s).size).to eq(1)
|
||||||
expect(emails_sent_to(expert2.email.to_s).size).to eq(1)
|
expect(emails_sent_to(expert2.email.to_s).size).to eq(1)
|
||||||
invitation_email = open_email(expert.email.to_s)
|
invitation_email = open_email(expert.email.to_s)
|
||||||
|
|
Loading…
Reference in a new issue