Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bloquer la sélection de détections déjà sélectionnées #760

Merged
merged 1 commit into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,14 @@ def _choice_js_cant_pick(page, locator, fill_content, exact_name):
expect(page.get_by_role("option", name=exact_name, exact=True)).not_to_be_visible()

return _choice_js_cant_pick


@pytest.fixture
def choice_js_option_disabled(db, page):
def _choice_js_cant_pick(page, locator, exact_name):
page.query_selector(locator).click()
page.wait_for_selector("input:focus", state="visible", timeout=2_000)
element = page.locator(locator).locator("xpath=..").locator(".choices__item--choice")
expect(element.get_by_role("option", name=exact_name, exact=True))

return _choice_js_cant_pick
68 changes: 65 additions & 3 deletions sv/static/sv/fichezone_form.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
let pickedDetections = []
let allChoices = []

function rebuildDetectionOptions(detectionChoices){
detectionChoices.enable()
const currentChoices = detectionChoices.passedElement.optionsAsChoices()
const updatedChoices = currentChoices.map(choice => ({
value: choice.value,
label: choice.label,
disabled: pickedDetections.includes(choice.value),
selected: choice.selected
}));
detectionChoices.clearChoices()
detectionChoices.setChoices(updatedChoices, 'value', 'label', false);
}


function rebuildChoicesOptions(){
allChoices.forEach(choices => { rebuildDetectionOptions(choices)})
}

function initializeChoices(elementId) {
options = {
searchResultLimit: 500,
Expand All @@ -9,8 +30,14 @@ function initializeChoices(elementId) {
noResultsText: 'Aucun résultat trouvé',
noChoicesText: 'Aucune fiche détection à sélectionner',
searchFields: ['label'],
};
new Choices(document.getElementById(elementId), options);
}
let choices = new Choices(document.getElementById(elementId), options)
choices.passedElement.element.addEventListener('change', event=> {
pickedDetections.push(event.detail.value)
rebuildChoicesOptions()
})
allChoices.push(choices)
rebuildDetectionOptions(choices)
}

function initializeAllChoices() {
Expand All @@ -20,6 +47,14 @@ function initializeAllChoices() {
}
}

function initializepickedDetections() {
allChoices.forEach((detectionChoice) =>{
detectionChoice.getValue().forEach((item) =>{
pickedDetections.push(item.value)
})
} )
}


function getNextIdToUse(){
let num = 0
Expand All @@ -36,7 +71,7 @@ function addZoneInfesteeForm() {
document.getElementById('zones-infestees').insertAdjacentHTML('beforeend', newTabTemplate);
const newDeleteBtn = document.querySelector(`#modal-delete-zi-confirmation-${nextIdToUse} .delete-zone-infestee`)
newDeleteBtn.addEventListener("click", removeZoneInfesteeForm)
new Choices(document.getElementById(`id_zoneinfestee_set-${nextIdToUse}-detections`), options);
initializeChoices(`id_zoneinfestee_set-${nextIdToUse}-detections`)
updatetotalFormsInput()
}

Expand All @@ -57,17 +92,44 @@ function removeZoneInfesteeForm(event){

dsfr(event.target.closest("dialog")).modal.conceal()
updatetotalFormsInput()

allChoices.forEach((choices) =>{
if (zoneElement.contains(choices.passedElement.element)){
allChoices = allChoices.filter(item => item !== choices)
const selectedValues = choices.getValue(true)
pickedDetections = pickedDetections.filter(item => !selectedValues.includes(item))
}
})
rebuildChoicesOptions()
}

function enableAllOptions(){
// Some options are disabled so that the user can't pick the detection twice in different pickers
// But we need to re-enabled the options because disabled choices are not sent in the form
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set
allChoices.forEach(detectionChoices =>{
Array.from(detectionChoices.passedElement.element.options).forEach(option => {
option.disabled = false
})
})
}

document.addEventListener('DOMContentLoaded', function() {

initializeChoices('id_detections_hors_zone');
initializeAllChoices();
initializepickedDetections();
rebuildChoicesOptions();
const addZoneButton = document.getElementById('add-zone-infestee');
addZoneButton.addEventListener('click', function(event) {
event.preventDefault();
addZoneInfesteeForm();
});
document.querySelectorAll("button.delete-zone-infestee").forEach(element => element.addEventListener("click", removeZoneInfesteeForm))

document.getElementById("save-btn").addEventListener("click", event =>{
event.preventDefault()
enableAllOptions()
document.getElementById("fiche-zone-delimitee-form").submit()
})
});
2 changes: 2 additions & 0 deletions sv/tests/test_fichezonedelimitee_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def test_cant_have_same_detection_in_hors_zone_infestee_and_zone_infestee(live_s
form_page = FicheZoneDelimiteeFormPage(page, choice_js_fill)

form_page.goto_create_form_page(live_server, evenement)
page.evaluate("window.rebuildDetectionOptions = function() {};") # Bypass front-end protection
form_page.fill_form(fiche_zone_delimitee, zone_infestee, (fiche_detection,), (fiche_detection,))
form_page.save()

Expand All @@ -209,6 +210,7 @@ def test_cant_have_same_detection_in_zone_infestee_forms(live_server, page: Page
form_page = FicheZoneDelimiteeFormPage(page, choice_js_fill)

form_page.goto_create_form_page(live_server, evenement)
page.evaluate("window.rebuildDetectionOptions = function() {};") # Bypass front-end protection
form_page.fill_form(fiche_zone_delimitee, zone_infestee1, (), (fiche_detection,))
form_page.add_new_zone_infestee(zone_infestee2, (fiche_detection,))
form_page.save()
Expand Down
69 changes: 69 additions & 0 deletions sv/tests/test_fichezonedelimitee_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ def test_update_form_cant_have_same_detection_in_hors_zone_infestee_and_zone_inf

form_page = FicheZoneDelimiteeFormPage(page, choice_js_fill)
page.goto(f"{live_server.url}{fiche_zone_delimitee.get_update_url()}")
page.wait_for_function("pickedDetections !== undefined")
page.evaluate("pickedDetections.push = function() {};")
page.evaluate("pickedDetections = [];") # Bypass front-end protection
page.evaluate("window.rebuildChoicesOptions();")
form_page.select_detections_in_zone_infestee(0, (fiche_detection,))
form_page.save()
expect(
Expand All @@ -159,6 +163,7 @@ def test_update_form_cant_have_same_detection_in_two_zone_infestee(live_server,
fiche_detection.save()
form_page = FicheZoneDelimiteeFormPage(page, choice_js_fill)
page.goto(f"{live_server.url}{fiche_zone_delimitee.get_update_url()}")
page.evaluate("window.rebuildDetectionOptions = function() {};") # Bypass front-end protection
form_page.add_new_zone_infestee(ZoneInfesteeFactory(), (fiche_detection,))
form_page.save()
expect(
Expand Down Expand Up @@ -336,3 +341,67 @@ def test_shows_correct_organisme_and_statut(live_server, page: Page):

expect(page.get_by_text(str(evenement.organisme_nuisible))).to_be_visible()
expect(page.get_by_text(str(evenement.statut_reglementaire))).to_be_visible()


def test_update_form_cant_have_same_detection_in_hors_zone_infestee_and_zone_infestee_check_ui(
live_server,
page: Page,
choice_js_fill,
choice_js_option_disabled,
):
fiche_detection = FicheDetectionFactory()
fiche_zone_delimitee = FicheZoneFactory()
evenement = fiche_detection.evenement
evenement.fiche_zone_delimitee = fiche_zone_delimitee
evenement.save()
ZoneInfesteeFactory(fiche_zone_delimitee=fiche_zone_delimitee)
fiche_detection.hors_zone_infestee = fiche_zone_delimitee
fiche_detection.save()

FicheZoneDelimiteeFormPage(page, choice_js_fill)
page.goto(f"{live_server.url}{fiche_zone_delimitee.get_update_url()}")
choice_js_option_disabled(
page,
"#zones-infestees .fr-col-4:nth-of-type(1) .choices__input--cloned:first-of-type",
str(fiche_detection.numero),
)


def test_update_form_cant_have_same_detection_in_hors_zone_infestee_and_in_new_zone_infestee_check_ui(
live_server,
page: Page,
choice_js_fill,
choice_js_option_disabled,
):
fiche_detection = FicheDetectionFactory()
fiche_zone_delimitee = FicheZoneFactory()
evenement = fiche_detection.evenement
evenement.fiche_zone_delimitee = fiche_zone_delimitee
evenement.save()
ZoneInfesteeFactory(fiche_zone_delimitee=fiche_zone_delimitee)
fiche_detection.hors_zone_infestee = fiche_zone_delimitee
fiche_detection.save()
other_detection = FicheDetectionFactory(evenement=evenement)

FicheZoneDelimiteeFormPage(page, choice_js_fill)
page.goto(f"{live_server.url}{fiche_zone_delimitee.get_update_url()}")

form_page = FicheZoneDelimiteeFormPage(page, choice_js_fill)
form_page.add_new_zone_infestee(ZoneInfesteeFactory.build(), ())
choice_js_option_disabled(
page,
"#zones-infestees .fr-col-4:nth-of-type(2) .choices__input--cloned:first-of-type",
str(fiche_detection.numero),
)

choice_js_fill(
page,
"#zones-infestees .fr-col-4:nth-of-type(2) .choices__input--cloned:first-of-type",
str(other_detection.numero),
str(other_detection.numero),
)
choice_js_option_disabled(
page,
".fichezoneform__detections-hors-zone-infestee .choices__list--multiple",
str(other_detection.numero),
)
Loading