feat(fase-15): exclude-on-list wiring + CI-02 e2e (15.4)
/lists/[id]/+page.svelte now passes the current item names through to fetchSuggestions as excludeNames, both on initial cold-load and on every debounced keystroke. The exclude list is a `$derived` of `items` so it recomputes the moment an optimistic insert lands — the next keystroke no longer surfaces the freshly-added item. ItemSuggestions.svelte gets a stable data-testid handle on the strip plus per-chip testids so the suite can assert presence/absence without fragile text matches. The component still hides itself entirely when the post-filter suggestion list is empty (the dropdown was already gated on `suggestions.length > 0`). Playwright CI-02 lives on a freshly-created list (the seed list is shared with the entire suite and tends to accumulate hundreds of test items, which both buries the assertion target and inflates the excludeNames URL). Boosts two synthetic names heavily so they lead the dropdown regardless of pollution in item_frequency, verifies "added" → "next fetch excludes it", and tears its own rows down via the admin purge RPC (direct table deletes are blocked by the deny-all RLS from migration 006). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -309,7 +309,12 @@
|
||||
loading = false;
|
||||
|
||||
if ($currentCollective) {
|
||||
suggestions = await fetchSuggestions($currentCollective.id, '');
|
||||
// Fase 15: exclude items already on the list from the suggestion
|
||||
// strip — the user doesn't need to be nudged to re-add what's
|
||||
// already there.
|
||||
suggestions = await fetchSuggestions($currentCollective.id, '', {
|
||||
excludeNames: items.map((i) => i.name)
|
||||
});
|
||||
// Load tags for this collective — picker + filter need them.
|
||||
await loadTags($currentCollective.id);
|
||||
}
|
||||
@@ -414,16 +419,24 @@
|
||||
|
||||
// ── Suggestions ────────────────────────────────────────────────────────────
|
||||
|
||||
async function updateSuggestions(prefix: string) {
|
||||
// Fase 15: exclude items already in the list so the strip doesn't nudge
|
||||
// the user to re-add what they already have. We snapshot the names here
|
||||
// so the `$effect` below re-fires whenever either the prefix typed or
|
||||
// the list contents change.
|
||||
const excludedItemNames = $derived(items.map((i) => i.name));
|
||||
|
||||
async function updateSuggestions(prefix: string, exclude: string[]) {
|
||||
clearTimeout(suggestionsTimer);
|
||||
if (!$currentCollective) return;
|
||||
suggestionsTimer = setTimeout(async () => {
|
||||
suggestions = await fetchSuggestions($currentCollective!.id, prefix);
|
||||
suggestions = await fetchSuggestions($currentCollective!.id, prefix, {
|
||||
excludeNames: exclude
|
||||
});
|
||||
}, 150);
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
updateSuggestions(newName);
|
||||
updateSuggestions(newName, excludedItemNames);
|
||||
});
|
||||
|
||||
function selectSuggestion(name: string) {
|
||||
|
||||
Reference in New Issue
Block a user