feat: Add Help menu with Check for Updates action

Menu implementation:
- Added menu bar to MainWindow
- Help menu with 'Check for Updates...' action
- Signal-based architecture for async update check
- Action triggers check_for_updates signal

Test coverage:
- 3 new tests for menu bar functionality
- Test menu bar creation
- Test signal exists and is callable
- Test callback method exists
- All 146 tests passing, 86% coverage

Design:
- Decoupled menu from update logic
- Emits signal that main app listens to
- Allows async update check without blocking UI
This commit is contained in:
claudi 2026-01-29 08:35:21 +01:00
parent af8e417197
commit 2896f6ba5c
2 changed files with 58 additions and 1 deletions

View file

@ -3,7 +3,7 @@
from pathlib import Path
from typing import Optional
from PySide6.QtCore import QSize, Qt, QUrl
from PySide6.QtCore import QSize, Qt, QUrl, Signal
from PySide6.QtWidgets import QMainWindow, QToolBar, QVBoxLayout, QWidget
from webdrop_bridge.config import Config
@ -173,6 +173,9 @@ class MainWindow(QMainWindow):
integration with the native filesystem.
"""
# Signals
check_for_updates = Signal()
def __init__(
self,
config: Config,
@ -202,6 +205,9 @@ class MainWindow(QMainWindow):
# Create navigation toolbar (Kiosk-mode navigation)
self._create_navigation_toolbar()
# Create menu bar
self._create_menu_bar()
# Create drag interceptor
self.drag_interceptor = DragInterceptor()
@ -341,6 +347,25 @@ class MainWindow(QMainWindow):
)
toolbar.addAction(refresh_action)
def _create_menu_bar(self) -> None:
"""Create menu bar with Help menu and update check action."""
menu_bar = self.menuBar()
# Help menu
help_menu = menu_bar.addMenu("Help")
# Check for Updates action
check_updates_action = help_menu.addAction("Check for Updates...")
check_updates_action.triggered.connect(self._on_check_for_updates)
def _on_check_for_updates(self) -> None:
"""Handle check for updates menu action.
Emits the check_for_updates signal to allow the main application
to perform the update check asynchronously.
"""
self.check_for_updates.emit()
def _navigate_home(self) -> None:
"""Navigate to the home (start) URL."""
home_url = self.config.webapp_url

View file

@ -323,6 +323,38 @@ class TestMainWindowSignals:
mock_handler.assert_called_once()
class TestMainWindowMenuBar:
"""Test menu bar and menu actions."""
def test_menu_bar_created(self, qtbot, sample_config):
"""Test menu bar is created."""
window = MainWindow(sample_config)
qtbot.addWidget(window)
menu_bar = window.menuBar()
assert menu_bar is not None
def test_window_has_check_for_updates_signal(self, qtbot, sample_config):
"""Test window has check_for_updates signal."""
window = MainWindow(sample_config)
qtbot.addWidget(window)
# Test that signal exists
assert hasattr(window, "check_for_updates")
# Test that signal is callable (can be emitted)
assert callable(window.check_for_updates.emit)
def test_on_check_for_updates_method_exists(self, qtbot, sample_config):
"""Test _on_check_for_updates method exists."""
window = MainWindow(sample_config)
qtbot.addWidget(window)
# Test that the method exists
assert hasattr(window, "_on_check_for_updates")
assert callable(window._on_check_for_updates)
class TestMainWindowStylesheet:
"""Test stylesheet application."""