bud panels duplicate-add guard: server-side already_present flag + client-side error Brief w. FYI flash highlight on the existing entry — for each of the three #id_bud_btn panels (My Buds / post-share / gatekeeper-invite), the JSON response from add_bud / share_post / invite_gamer now carries {already_present, recipient_display, recipient_user_id}; bud-btn.js branches on already_present → calls new Brief.showDuplicateBanner({display_name, target_selector}) instead of the normal onSuccess append; banner title reads @<username> is already present, NVM dismisses, FYI dismisses AND eases in the .bud-duplicate-flash class (color: var(--terUser); text-shadow: 0 0 .5em var(--ninUser); transition: 600ms) onto the existing element (.bud-entry .bud-name / .post-recipient[data-user-id=…] / .gate-slot.filled[data-user-id=…]); gatekeeper "already present" = recipient is either GateSlot.FILLED + gamer OR has TableSeat OR has a pending RoomInvite (highlight target only set when seated — pending invites have no visible slot); .post-recipient chips + .gate-slot.filled cells gain data-user-id so the FYI selector can find them; my_buds.html now loads note.js via the {% block scripts %} pattern (Brief module is required by the duplicate banner path); bonus: latent test_jasmine.py bug fixed — "0 failures" in result.text matched "10 failures" / "20 failures" / etc, silently passing up to 99 failed specs; replaced w. re.search(r"(?<!\d)0 failures\b", …) (caught my new red specs, would've caught any prior Jasmine regression); 18 new ITs + 10 new Jasmine specs + 3 new FTs (one per panel) — TDD
Some checks failed
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline failed

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-12 16:40:15 -04:00
parent 264ed5968e
commit be919c7aff
19 changed files with 738 additions and 38 deletions

View File

@@ -69,13 +69,54 @@ const Brief = (() => {
showBanner(data && data.brief);
}
// Error-variant banner for "@<username> is already present". Distinct
// from showBanner because it's purely client-side (no Brief DB row);
// title carries the recipient handle; there's no date/square/post_url;
// FYI is a <button> (no navigation) that toggles `.bud-duplicate-flash`
// onto a caller-supplied target element + dismisses. NVM just dismisses.
function showDuplicateBanner(opts) {
if (!opts || !opts.display_name) return;
var banner = document.createElement('div');
banner.className = 'note-banner note-banner--duplicate';
banner.innerHTML =
'<div class="note-banner__body">' +
'<p class="note-banner__title">@' + _esc(opts.display_name) + ' is already present</p>' +
'</div>' +
'<button type="button" class="btn btn-cancel note-banner__nvm">NVM</button>' +
'<button type="button" class="btn btn-info note-banner__fyi">FYI</button>';
banner.querySelector('.note-banner__nvm').addEventListener('click', function () {
banner.remove();
});
banner.querySelector('.note-banner__fyi').addEventListener('click', function () {
if (opts.target_selector) {
var target = document.querySelector(opts.target_selector);
if (target) target.classList.add('bud-duplicate-flash');
}
banner.remove();
});
var anchor = document.getElementById('id_brief_banner_anchor')
|| document.querySelector('h2');
if (anchor && anchor.parentNode) {
anchor.parentNode.insertBefore(banner, anchor.nextSibling);
} else {
document.body.insertBefore(banner, document.body.firstChild);
}
}
function _esc(str) {
var d = document.createElement('div');
d.textContent = str || '';
return d.innerHTML;
}
return { showBanner: showBanner, handleSaveResponse: handleSaveResponse };
return {
showBanner: showBanner,
showDuplicateBanner: showDuplicateBanner,
handleSaveResponse: handleSaveResponse,
};
})();
// Backwards-compat shim — to be removed once the codebase uniformly uses Brief.