создан механизм для создания меню для разных сравнений через drap-and-drop

This commit is contained in:
2026-08-20 12:29:07 +03:00
parent 3f2d5caa4a
commit 81fd030846
6 changed files with 727 additions and 22 deletions

View File

@@ -0,0 +1,90 @@
from pathlib import Path
from ui_builder.manager import DEFAULT_HOCKEY_PLAYER_SELECTION_PANELS, UIBuilderManager
ROOT = Path(__file__).resolve().parents[1]
APP_JS = (ROOT / "ui_builder/static/app.js").read_text(encoding="utf-8")
APP_PY = (ROOT / "app.py").read_text(encoding="utf-8")
MAPPING = (ROOT / "hockey_data/mapping_context.py").read_text(encoding="utf-8")
STYLES = (ROOT / "ui_builder/static/styles.css").read_text(encoding="utf-8")
def test_old_hockey_config_gets_default_player_selection_panels(tmp_path: Path):
manager = UIBuilderManager(tmp_path)
config = {
"version": 21,
"project_name": "Hockey",
"tabs": [{"id": "main", "label": "Игра"}],
"components": [{"id": "h", "type": "hockey_penalty_dashboard", "action_id": "hockey_game"}],
}
normalized = manager._normalize(config)
panels = normalized["player_selection_panels"]
assert [item["id"] for item in panels] == [item["id"] for item in DEFAULT_HOCKEY_PLAYER_SELECTION_PANELS]
assert {item["id"]: item["slots"] for item in panels} == {
"compare_home": 2,
"compare_away": 2,
"compare_mixed": 2,
"three_stars": 3,
"selected_player": 1,
}
def test_player_selection_panels_are_persisted_with_quick_panel_settings():
assert 'player_panels = payload.get("player_selection_panels", [])' in APP_PY
assert 'draft_config["player_selection_panels"] = player_panels' in APP_PY
assert 'published_config["player_selection_panels"]' in APP_PY
assert 'player_selection_panels: normalizedPlayerPanels' in APP_JS
def test_runtime_player_slots_accept_roster_drag_drop_and_generate_identifiers():
for token in (
"function renderHockeyPlayerSelectionWindows()",
'readHockeyDragData(event, "player")',
"hockeySetPlayerSelectionSlot(panel",
"player_select.${panelId}.player${slot}_${field}",
'"db_id"',
'"team_id"',
'"side"',
):
assert token in APP_JS
assert 'panel.rule === "home"' in APP_JS
assert 'panel.rule === "away"' in APP_JS
assert 'panel.rule === "different_teams"' in APP_JS
def test_single_selected_player_panel_mirrors_legacy_signature_context():
assert '"selected_player"' in APP_JS or 'selected_player' in APP_JS
assert "sync_selected_player" in APP_JS
assert "selected_player_id:" in APP_JS
assert "selected_player_team_id:" in APP_JS
def test_mapping_catalog_exposes_dynamic_player_selection_groups():
assert 'r"^player_select\\.([A-Za-z0-9_]+)\\.(.+)$"' in MAPPING
assert 'Игровые выборки ·' in MAPPING
assert "DB ID" in MAPPING
assert "ID команды" in MAPPING
def test_player_panels_are_collapsible_and_have_editor_ui():
assert "hockey-player-select-panel" in STYLES
assert ".hockey-player-select-panel.is-collapsed .hockey-player-select-body" in STYLES
assert 'data-player-panel-field="slots"' in APP_JS
assert 'data-player-panel-field="rule"' in APP_JS
assert 'data-player-panel-add' in APP_JS
def test_all_overlay_sequences_latch_onair_state_for_lower_dock():
start = APP_JS.index("function trackRuntimeOverlayCommands")
end = APP_JS.index("async function sendRuntimeVmixSequence", start)
block = APP_JS[start:end]
assert "state.shortcutSequenceOverlayState.set(ownerSequenceId, true);" in block
assert "state.shortcutSequenceOverlayState.set(ownerSequenceId, false);" in block
assert "refreshQuickPanelOnAirClasses();" in block
def test_player_panel_id_edit_rerenders_row_so_followup_fields_use_new_id():
assert 'const eventName = field === "id"' in APP_JS
assert 'if (field === "id") {' in APP_JS
assert "draftPlayerPanels = normalized;" in APP_JS
assert "renderEditor();" in APP_JS