Skip to content

Commit 1fe21de

Browse files
committed
add validation status
1 parent 0bcbb6e commit 1fe21de

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

app/ui.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,10 @@ def create_action_panel(self) -> None:
292292
self.unsupported_actions_table_widget.setFixedHeight(400)
293293
self.action_panel_layout.addWidget(self.unsupported_actions_table_widget)
294294

295+
self.validation_status_label = QLabel("Binding status: Not evaluated", self.action_panel)
296+
self.validation_status_label.setStyleSheet("color: #666666;")
297+
self.action_panel_layout.addWidget(self.validation_status_label)
298+
295299
def toggle_modifier(self) -> None:
296300
self.modifier_enabled = not self.modifier_enabled
297301
self.modifier_button.setText(
@@ -318,6 +322,7 @@ def set_default_bindings(self) -> None:
318322
self.load_joystick_mappings()
319323
self.update_joystick_buttons()
320324
self.binding_planner_context.default_profile = self.build_control_profile_snapshot()
325+
self.update_validation_status_indicator(None)
321326

322327
def select_control_map(self, index: int) -> None:
323328
if index < 0 or index >= len(self.exported_control_maps):
@@ -417,6 +422,27 @@ def _update_unsupported_actions_label(self) -> None:
417422
self.unsupported_actions_label.setText("Unsupported Actions (none)")
418423
self.unsupported_actions_label.setStyleSheet("color: #666666;")
419424

425+
def update_validation_status_indicator(self, report: Optional[ValidationReport]) -> None:
426+
if report is None:
427+
self.validation_status_label.setText("Binding status: Not evaluated")
428+
self.validation_status_label.setStyleSheet("color: #666666;")
429+
return
430+
431+
error_count = sum(1 for issue in report.issues if issue.level.lower() == "error")
432+
warning_count = sum(
433+
1 for issue in report.issues if issue.level.lower() in {"warn", "warning"}
434+
)
435+
436+
if error_count:
437+
self.validation_status_label.setText(f"Binding status: {error_count} error(s)")
438+
self.validation_status_label.setStyleSheet("color: #cc3300; font-weight: bold;")
439+
elif warning_count:
440+
self.validation_status_label.setText(f"Binding status: {warning_count} warning(s)")
441+
self.validation_status_label.setStyleSheet("color: #cc7a00; font-weight: bold;")
442+
else:
443+
self.validation_status_label.setText("Binding status: OK")
444+
self.validation_status_label.setStyleSheet("color: #2e7d32; font-weight: bold;")
445+
420446
def load_joystick_mappings(self) -> None:
421447
self.unsupported_actions.clear()
422448
self.left_joystick_config.clear_mappings()
@@ -429,6 +455,7 @@ def load_joystick_mappings(self) -> None:
429455
self.apply_default_bindings()
430456

431457
self.update_unsupported_actions_table()
458+
self.update_validation_status_indicator(None)
432459

433460
def process_action_map(self, actionmap: ActionMap) -> None:
434461
for action in actionmap.action:
@@ -871,6 +898,8 @@ def update_control_map(self) -> None:
871898
self.control_map = export_map
872899
unparse(export_map)
873900

901+
self.update_validation_status_indicator(report)
902+
874903
def remove_selected_action(self) -> None:
875904
"""
876905
Remove the selected action from the button's mappings.

tests/test_ui.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from app.models.joystick import JoyAction
1010
from PyQt6.QtWidgets import QApplication, QDialogButtonBox
1111
from PyQt6.QtCore import Qt
12+
from app.domain import ValidationIssue, ValidationReport
1213
from app.ui import ControlMapperApp, joystick_buttons
1314
from app.components.settings_dialog import SettingsDialog
1415

@@ -288,7 +289,14 @@ def test_process_rebind_records_unsupported(main_window: ControlMapperApp) -> No
288289

289290
def test_unsupported_actions_label_updates(main_window: ControlMapperApp) -> None:
290291
"""Label should reflect the number of unsupported mappings."""
291-
assert main_window.unsupported_actions_label.text() == "Unsupported Actions (none)"
292+
main_window.update_unsupported_actions_table()
293+
initial_count = len(main_window.unsupported_actions)
294+
expected_initial = (
295+
"Unsupported Actions (none)"
296+
if initial_count == 0
297+
else f"Unsupported Actions ({initial_count})"
298+
)
299+
assert main_window.unsupported_actions_label.text() == expected_initial
292300

293301
entry: Dict[str, Any] = {
294302
"action_name": "test_action",
@@ -298,8 +306,27 @@ def test_unsupported_actions_label_updates(main_window: ControlMapperApp) -> Non
298306
}
299307
main_window.unsupported_actions.append(entry)
300308
main_window.update_unsupported_actions_table()
301-
assert main_window.unsupported_actions_label.text() == "Unsupported Actions (1)"
309+
assert (
310+
main_window.unsupported_actions_label.text() == f"Unsupported Actions ({initial_count + 1})"
311+
)
302312

303313
main_window.unsupported_actions.clear()
304314
main_window.update_unsupported_actions_table()
305315
assert main_window.unsupported_actions_label.text() == "Unsupported Actions (none)"
316+
317+
318+
def test_validation_status_label(main_window: ControlMapperApp) -> None:
319+
"""Validation status label reflects report severity."""
320+
main_window.update_validation_status_indicator(None)
321+
assert main_window.validation_status_label.text() == "Binding status: Not evaluated"
322+
323+
report = ValidationReport()
324+
report.add(ValidationIssue(level="warning", message="example warning"))
325+
main_window.update_validation_status_indicator(report)
326+
assert main_window.validation_status_label.text() == "Binding status: 1 warning(s)"
327+
328+
report = ValidationReport()
329+
report.add(ValidationIssue(level="error", message="example error"))
330+
report.add(ValidationIssue(level="ERROR", message="another"))
331+
main_window.update_validation_status_indicator(report)
332+
assert main_window.validation_status_label.text() == "Binding status: 2 error(s)"

todo.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
- [ ] Add packaging docs to `README.md` once the build path is confirmed.
99

1010
## Codebase Cleanup
11-
- [ ] Stabilize the remaining TODOs in `app/ui.py` (action panel refresh, unsupported actions table, export flow). *Joystick side mapping hardened; action panel refresh auto-syncs; unsupported table now tracks unknown buttons/sliders; export work still open.*
11+
- [ ] Stabilize the remaining TODOs in `app/ui.py` (action panel refresh, unsupported actions table, export flow). *Joystick side mapping hardened; action panel refresh auto-syncs; unsupported table counts + styles entries; export work still open.*
1212
- [ ] Extract joystick binding state management into dedicated service modules to trim the QWidget class size.
1313
- [ ] Normalize data flow between `app/models` and `app/utils` (remove circular imports and duplicated helpers).
1414
- [ ] Audit `app/models/exported_configmap_xml.py` for dead fields and tighten type hints.

0 commit comments

Comments
 (0)