From f97fc3e6edbd9afd506e8c390f7be5181a4b1f3a Mon Sep 17 00:00:00 2001 From: andreasgriffin Date: Tue, 4 Aug 2026 12:32:17 +0200 Subject: [PATCH] Show Open button for enabled plugins --- .../plugin_framework/plugin_list_widget.py | 19 +++++++- .../test_paid_plugin_client.py | 5 +- tests/non_gui/test_external_plugins.py | 46 ++++++++++++++++++- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/bitcoin_safe/plugin_framework/plugin_list_widget.py b/bitcoin_safe/plugin_framework/plugin_list_widget.py index 17b8b46b..6acc531c 100644 --- a/bitcoin_safe/plugin_framework/plugin_list_widget.py +++ b/bitcoin_safe/plugin_framework/plugin_list_widget.py @@ -292,6 +292,10 @@ def set_status_text(self, status_text: str) -> None: self.status_label.setText(status_text) self.status_label.setVisible(bool(status_text)) + def set_body_content_visible(self, visible: bool) -> None: + super().set_body_content_visible(visible) + self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed) + def set_enable_toggle( self, checked: bool, @@ -433,7 +437,7 @@ def _create_additional_sections(self) -> None: return None def _create_action_buttons(self) -> None: - return None + self.open_button = self.add_management_button() def _on_enabled_changed(self, _enabled: bool) -> None: self.updateUi() @@ -461,7 +465,14 @@ def _combined_status_text(self) -> str: return status_text def _update_action_buttons(self) -> None: - return None + can_select_node = self._can_select_node() + self._set_button_action( + button=self.open_button, + text=self.tr("Open"), + callback=self._select_plugin_node, + visible=can_select_node, + enable=can_select_node, + ) def _enable_toggle_visible(self) -> bool: return self.plugin.supports_enable_toggle() @@ -487,10 +498,12 @@ def updateUi(self) -> None: class ExternalPluginWidget(PluginWidget): def _create_action_buttons(self) -> None: + super()._create_action_buttons() self.update_button = self.add_spinning_detail_button() self.delete_button = self.add_spinning_management_button() def _update_action_buttons(self) -> None: + super()._update_action_buttons() self._set_button_action( button=self.update_button, text=self.plugin.update_button_text(), @@ -674,6 +687,7 @@ def _plan_options(self) -> tuple[tuple[str, str], ...]: return tuple(options) def _create_action_buttons(self) -> None: + super()._create_action_buttons() self.start_trial_button = SpinningButton( text="", parent=self.subscription_buttons_container, @@ -694,6 +708,7 @@ def _enable_toggle_visible(self) -> bool: return self.plugin.supports_enable_toggle() and self.plugin.subscription_allows_access() def _update_action_buttons(self) -> None: + super()._update_action_buttons() self.management_title_label.setText(self.tr("Subscription:")) displayed_subscription_manager = self.plugin.displayed_subscription_manager supports_manage_subscription = displayed_subscription_manager.supports_manage_subscription() diff --git a/tests/gui/qt/plugin_framework/test_paid_plugin_client.py b/tests/gui/qt/plugin_framework/test_paid_plugin_client.py index 8faf34ad..1b619db3 100644 --- a/tests/gui/qt/plugin_framework/test_paid_plugin_client.py +++ b/tests/gui/qt/plugin_framework/test_paid_plugin_client.py @@ -1827,8 +1827,9 @@ def test_external_paid_plugin_places_update_button_with_action_controls( assert widget.update_button.parentWidget() is widget.action_buttons_container assert widget.delete_button.parentWidget() is widget.action_buttons_container - assert widget.action_buttons_layout.itemAt(0).widget() is widget.update_button - assert widget.action_buttons_layout.itemAt(1).widget() is widget.delete_button + assert widget.action_buttons_layout.itemAt(0).widget() is widget.open_button + assert widget.action_buttons_layout.itemAt(1).widget() is widget.update_button + assert widget.action_buttons_layout.itemAt(2).widget() is widget.delete_button assert widget.manage_subscription_button.parentWidget() is widget.management_buttons_container assert widget.refresh_subscription_button.parentWidget() is widget.management_buttons_container finally: diff --git a/tests/non_gui/test_external_plugins.py b/tests/non_gui/test_external_plugins.py index 42acd31a..b00b8dd8 100644 --- a/tests/non_gui/test_external_plugins.py +++ b/tests/non_gui/test_external_plugins.py @@ -55,7 +55,14 @@ from btcpay_tools.config import BTCPayConfig, PlanDuration from packaging.version import Version from PyQt6.QtGui import QColor, QIcon, QPixmap -from PyQt6.QtWidgets import QApplication, QHBoxLayout, QStackedWidget, QVBoxLayout, QWidget +from PyQt6.QtWidgets import ( + QApplication, + QHBoxLayout, + QSizePolicy, + QStackedWidget, + QVBoxLayout, + QWidget, +) from bitcoin_safe import __version__ from bitcoin_safe.config import UserConfig @@ -2349,6 +2356,38 @@ def record_emission() -> None: manager.close() +def test_plugin_widget_shows_open_button_only_while_enabled( + qapp: QApplication, monkeypatch: pytest.MonkeyPatch +) -> None: + del qapp + client = _DisplayMetadataPluginClient() + opened: list[bool] = [] + + def record_open() -> bool: + opened.append(True) + return True + + monkeypatch.setattr(client.node, "select", record_open) + widget = client.create_plugin_widget() + + try: + assert not widget.open_button.isHidden() + assert widget.open_button.text() == "Open" + assert widget.open_button.parentWidget() is widget.action_buttons_container + + widget.open_button.click() + assert opened == [True] + + client.set_enabled(False) + assert widget.open_button.isHidden() + + client.set_enabled(True) + assert not widget.open_button.isHidden() + finally: + widget.close() + client.close() + + def test_external_plugin_widget_orders_action_buttons_left_to_right(qapp: QApplication) -> None: del qapp client = _DisplayMetadataPluginClient() @@ -2373,8 +2412,11 @@ def test_external_plugin_widget_orders_action_buttons_left_to_right(qapp: QAppli assert not widget.update_button.isHidden() assert widget.delete_button.parentWidget() is widget.action_buttons_container assert isinstance(widget.action_buttons_layout, QVBoxLayout) - assert widget.action_buttons_layout.itemAt(0).widget() is widget.delete_button + assert widget.action_buttons_layout.itemAt(0).widget() is widget.open_button + assert widget.action_buttons_layout.itemAt(1).widget() is widget.delete_button + assert widget.open_button.isHidden() assert not widget.delete_button.isHidden() + assert widget.sizePolicy().verticalPolicy() == QSizePolicy.Policy.Fixed finally: widget.close() client.close()