Skip to content

fix(book-form): make contributor/author/publisher autocomplete race-proof#272

Merged
fabiodalez-dev merged 4 commits into
mainfrom
fix/contributor-autocomplete-race
Jul 20, 2026
Merged

fix(book-form): make contributor/author/publisher autocomplete race-proof#272
fabiodalez-dev merged 4 commits into
mainfrom
fix/contributor-autocomplete-race

Conversation

@fabiodalez-dev

@fabiodalez-dev fabiodalez-dev commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Problem

The book form's server-search Choices.js pickers — illustrator/translator/curator/colorist contributors, plus the author and publisher pickers — fetch matches from /api/search/autori on keystroke and feed them in via setChoices(). But Choices.js's own client-side Fuse filter (searchChoices, default true) races that async populate: for a short/partial query it renders the dropdown as "no results" before the fetch lands, and never re-filters — so fresh server results stay hidden until the next keystroke. The autocomplete looked broken for partial queries (e.g. typing rod showed nothing even though Rodari exists).

The backend was fine (/api/search/autori returns the matches); the results just weren't reaching the dropdown reliably.

Fix

On the three server-search pickers:

  • searchChoices: false — disable Choices' client Fuse filter so it can't hide server results.
  • setChoices(newChoices, 'value', 'label', true, false)replaceChoices=true drops the previous query's options (no stale results lingering now that the client filter is off) and clearSearchFlag=false leaves the user's in-progress search input untouched.

Verified on the live form (Playwright)

  • Typing a partial query (manz, rod, ein) reliably shows the matching existing authors/publishers.
  • Edge case (select-then-type): select a result → its chip is added and the input clears (normal) → type another query → after the async setChoices the typed text is NOT cleared and the earlier chip is preserved; selecting the second result yields both chips.
  • Enter-to-add-a-new contributor (adding new author #74) still works.
  • No console errors.

Test

tests/contributor-autocomplete-config.unit.php (9 assertions) locks in the structural fix — searchChoices: false on all three pickers and the replace=true, clearSearchFlag=false setChoices form, and guards against a revert to the old racy append form. The race itself is timing-dependent and can't be asserted deterministically, so behaviour is covered by the manual E2E above.

Pre-existing issue, independent of the 0.7.38-rc.1 bundle.

Summary by CodeRabbit

  • Correzioni
    • Migliorata la ricerca server-side per autori, contributori ed editori/publisher.
    • Le opzioni aggiornate sostituiscono sempre le precedenti, anche quando il server non trova risultati, evitando stati “stale” e senza cancellare il testo digitato.
    • Ridotti i conflitti tra filtraggio locale e risposte del server; migliorato anche il layout dell’input sotto i chip selezionati.
  • Test
    • Aggiunte verifiche di regressione automatiche per garantire il comportamento della ricerca e prevenire ricadute del fix async.

…roof

The illustrator/translator/curator/colorist pickers (and the author + publisher
pickers) fetch matches from /api/search/autori on keystroke and feed them via
setChoices(). Choices.js's own client-side Fuse filter (searchChoices, default
true) races that async populate: for a short/partial query it renders the
dropdown as 'no results' BEFORE the fetch lands and never re-filters, so fresh
server results are hidden until the next keystroke — the autocomplete looked
broken for partial queries.

Set searchChoices: false on the three server-search pickers so the client filter
can't hide server results, and make each server response setChoices(...,
replaceChoices=true, clearSearchFlag=false): replace drops the previous query's
options (no stale results lingering with the filter off), and clearSearchFlag=false
leaves the user's in-progress input untouched. Verified on the live form that
typing a partial query reliably shows matches, that selecting a result then
typing more preserves BOTH the typed text and the earlier chip, and that
Enter-to-add-a-new-contributor (#74) still works.

tests/contributor-autocomplete-config.unit.php locks in the structural fix (the
race is timing-dependent and can't be asserted deterministically).
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 653f0b0b-1338-4d7c-9fbc-08a617c9f2e7

📥 Commits

Reviewing files that changed from the base of the PR and between 0115166 and 3d61648.

📒 Files selected for processing (2)
  • app/Views/libri/partials/book_form.php
  • tests/contributor-autocomplete-config.unit.php

📝 Walkthrough

Walkthrough

Il form aggiorna la ricerca server-side dei picker Choices.js per autori, contributori ed editori, disabilitando il filtro locale, sostituendo anche risultati vuoti e preservando l’input. È stato centralizzato il layout dell’input ed esteso il test PHP di regressione.

Changes

Autocomplete server-side

Layer / File(s) Summary
Ricerca server-side e layout dei picker
app/Views/libri/partials/book_form.php
I tre picker usano searchChoices: false; gli handler applicano setChoices(..., true, false) anche con risultati vuoti. stackChoicesInput mantiene l’input su una riga separata sotto i chip.
Contratti di regressione
tests/contributor-autocomplete-config.unit.php
Il test PHP verifica la configurazione dei picker, la sostituzione senza reset, l’assenza della variante append, la gestione dei risultati vuoti e la dichiarazione di internalInput per gli autori.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: fabiodalez

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Il titolo descrive bene il fix principale sulle autocomplete di book-form per autori, contributori e editori, includendo il problema di race condition.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/contributor-autocomplete-race

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Views/libri/partials/book_form.php`:
- Around line 1425-1430: Remove the newChoices.length > 0 guards in
app/Views/libri/partials/book_form.php at lines 1425-1430, 2446-2448, and
2504-2508. Invoke authorsChoice.setChoices, choice.setChoices, and
publishersChoice.setChoices respectively with the existing arguments
unconditionally, including when newChoices is empty, so stale options are
cleared.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1abe6e1b-f4d7-42b3-9044-40bffe49e415

📥 Commits

Reviewing files that changed from the base of the PR and between 221f018 and 0115166.

📒 Files selected for processing (2)
  • app/Views/libri/partials/book_form.php
  • tests/contributor-autocomplete-config.unit.php

Comment thread app/Views/libri/partials/book_form.php Outdated
Address CodeRabbit on #272: with searchChoices:false the client-side filter is
off, so a `if (newChoices.length > 0)` guard before setChoices left the previous
query's options visible when a later search returned nothing — type "manz" then
a no-match query, and Manzini stayed shown. Call setChoices unconditionally on
all three server-search pickers (authors, contributors, publishers): replace
clears the dropdown even for an empty result set, while clearSearchFlag=false
still preserves the user's in-progress input.

Verified: after a matching query, a subsequent no-results query now empties the
dropdown. Guard test extended to assert no newChoices.length gate remains.
On the contributor (illustrator/translator/curator/colorist), author and
publisher pickers the Choices.js search input sat inline to the RIGHT of the last
selected chip, so you typed squeezed next to the chips instead of under them.

Add a shared stackChoicesInput(wrapper) helper that makes the chip row wrap and
drops the search field onto its own full-width line below the chips. It applies
the styles inline with !important (the compiled Choices CSS otherwise wins) and
re-applies them via a MutationObserver, because Choices.js autosizes the input's
inline width on every keystroke and would otherwise pull it back onto the chip
row. Replaces the authors-only forceInputWidth (which did the opposite, filling
the remaining inline space) so all three pickers share one behaviour.

Verified on the live form: with a chip selected the input is full-width and sits
below the chip on all three pickers; autocomplete and Enter-to-add still work; no
console errors.
…regression)

The stackChoicesInput refactor replaced the authors-only forceInputWidth
block, which also declared `const internalInput`. The authors picker's
#74 _onEnterKey monkey-patch and its ensureAuthorChoice helpers still
reference `internalInput`, so on the first keystroke the book form threw
"ReferenceError: internalInput is not defined" — breaking add-author-via-
Enter and the rest of the form's inline JS on both create and edit.

Restore the declaration right after `const wrapper = element.closest`.
Extend the config guard test (section E) to assert the authors picker
declares internalInput before its _onEnterKey patch, so a future refactor
that drops it fails the gate instead of shipping a broken form.

Verified live: create (author via Enter + illustrator autocomplete),
edit (add illustrator), delete (remove illustrator) all persist; console
clean.
@fabiodalez-dev
fabiodalez-dev merged commit 00e8c92 into main Jul 20, 2026
6 checks passed
Himura2la pushed a commit to hackerembassy/Pinakes that referenced this pull request Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant