Stage 17 (contour round 2): Grafana Live/reload, rate-limit, iOS reconnect, hint/plaque/make-move UX

- Grafana: disable Live (GF_LIVE_MAX_CONNECTIONS=0) so its WebSocket no longer trips caddy Basic-Auth and re-prompts; admin console gains a Grafana nav link
- deploy: force-recreate config-only services so reseeded Grafana dashboards / Caddyfile are actually picked up (the move-duration panel was invisible because the bind-mount went stale)
- rate-limit: raise per-user budget 120/40 -> 300/80; UI skips reloading on the echo of the player's own move (fewer requests, no double-load)
- iOS/Telegram reconnect: suppress the connection banner while backgrounded and for a short grace after resume; reconnect silently; wire visibilitychange + pageshow/pagehide + Telegram activated/deactivated (Bot API 8.0)
- hint button disabled when 0 hints remain; nudge button shows a disabled state on your own turn
- players plaque: invert so the active seat pops (accent chip, raised) and others recede
- make-move UX: a direct  commit button (no hold/popover); the Shuffle tab becomes ↩️ Reset while tiles are pending
This commit is contained in:
Ilia Denisov
2026-06-06 12:33:52 +02:00
parent 09fec2b83c
commit c94cd3c3bf
10 changed files with 110 additions and 48 deletions
+3 -4
View File
@@ -16,16 +16,15 @@ async function openGame(page: Page): Promise<void> {
await expect(page.locator('.pane')).toHaveCount(1);
}
test('placing a tile and confirming via 🏁 commits the move', async ({ page }) => {
test('placing a tile and confirming via commits the move', async ({ page }) => {
await openGame(page);
await page.locator('.rack .tile').first().click();
await page.locator('[data-cell]:not(.filled)').nth(30).click();
await expect(page.locator('[data-cell].pending')).toHaveCount(1);
await page.locator('.make').click(); // open the MakeMove popover (short tap)
await page.locator('.pop.go').click(); // "Make move ✅"
await page.locator('.make').click(); // ✅ commits the move directly (no popover)
// After the commit the placement is cleared: no pending tile, no 🏁 control.
// After the commit the placement is cleared: no pending tile, no control.
await expect(page.locator('[data-cell].pending')).toHaveCount(0);
await expect(page.locator('.make')).toBeHidden();
});
+1 -1
View File
@@ -25,6 +25,6 @@ test('guest reaches a board and previews a placement', async ({ page }) => {
// The score preview appears where the hints count used to be.
await expect(page.locator('.scores')).toContainText(/\d/);
// The contextual MakeMove control (🏁) appears once a tile is pending.
// The contextual MakeMove control () appears once a tile is pending.
await expect(page.locator('.make')).toBeVisible();
});