From a28b0fc0625e3191bb50fb319db09a9bba207450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=A7=D0=B5=D1=80=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Thu, 20 Aug 2026 11:23:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B5=D1=81=D0=BB=D0=B8=20=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=85=D0=BD=D0=B8=D0=B9=20=D1=81=D1=87=D0=B5=D1=82=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=B0=D0=BD,=20=D0=B8=20=D0=BF=D0=BE=D1=8F=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5,=20=D1=82=D0=BE=20=D0=BE=D0=BD=D0=BE?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B8=D0=B3=D1=80=D1=8B=D0=B2=D0=B0=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D1=81=D1=80=D0=B0=D0=B7=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_build77_penalty_overlay_auto_in.py | 24 +++++++++++++++++++ ui_builder/static/app.js | 18 ++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/test_build77_penalty_overlay_auto_in.py diff --git a/tests/test_build77_penalty_overlay_auto_in.py b/tests/test_build77_penalty_overlay_auto_in.py new file mode 100644 index 0000000..a71cd17 --- /dev/null +++ b/tests/test_build77_penalty_overlay_auto_in.py @@ -0,0 +1,24 @@ +from pathlib import Path + +APP_JS = (Path(__file__).resolve().parents[1] / "ui_builder" / "static" / "app.js").read_text(encoding="utf-8") + + +def test_ready_penalty_opens_target_when_scoreboard_is_live(): + start = APP_JS.index("async function rebalanceVmixPenaltyTargets") + end = APP_JS.index("function finishActionMatchesSource", start) + snippet = APP_JS[start:end] + assert "if (hockeyScoreboardIsLive())" in snippet + assert 'commands.push({ Function: `OverlayInput${overlay}In`, Input: target.input });' in snippet + + +def test_penalty_overlay_auto_in_does_not_retrigger_visible_target(): + start = APP_JS.index("async function rebalanceVmixPenaltyTargets") + end = APP_JS.index("function finishActionMatchesSource", start) + snippet = APP_JS[start:end] + assert "const targetWasVisible = Boolean(previous?.input)" in snippet + assert "if (!targetWasVisible)" in snippet + + +def test_existing_team_state_sync_logic_is_untouched(): + assert 'for (const key of ["home_delayed_penalty", "home_empty_net", "away_delayed_penalty", "away_empty_net"])' in APP_JS + assert "async function hockeySyncTeamStateOverlays" in APP_JS diff --git a/ui_builder/static/app.js b/ui_builder/static/app.js index 5135f98..f012fac 100644 --- a/ui_builder/static/app.js +++ b/ui_builder/static/app.js @@ -4539,6 +4539,24 @@ function startCustomTooltips() { commands.push({ Function: "SetText", Input: target.input, SelectedName: target.selected_name, Value: value }); if (mirror) mirror.lastValue = value; } + + // If the scoreboard is already on air and this penalty target was not + // previously assigned, bring the penalty plate on air immediately. + // Previously the text was updated here, but OverlayIn happened only + // when the whole scoreboard shortcut was executed again. + if (hockeyScoreboardIsLive()) { + const overlay = ["1", "2", "3", "4"].includes(String(target.overlay || "")) ? String(target.overlay) : "2"; + const targetWasVisible = Boolean(previous?.input) + && String(previous.input) === String(target.input) + && String(previous.overlay || overlay) === overlay; + if (!targetWasVisible) { + if (previous?.input && (String(previous.input) !== String(target.input) || String(previous.overlay || overlay) !== overlay)) { + const previousOverlay = ["1", "2", "3", "4"].includes(String(previous.overlay || "")) ? String(previous.overlay) : overlay; + commands.push({ Function: `OverlayInput${previousOverlay}Out`, Input: previous.input }); + } + commands.push({ Function: `OverlayInput${overlay}In`, Input: target.input }); + } + } } else { if (previous && hideUnused && target.auto_hide_on_finish !== false && target.input) { const overlay = ["1", "2", "3", "4"].includes(String(target.overlay || "")) ? String(target.overlay) : "2";