fix(jira-knowledge): replace hover tooltip with click-based popup for help button

Native Qt tooltips on macOS are unreliable (delayed or invisible). Replace
with a QFrame popup that appears on click, positioned below the ? button,
and closes when clicking elsewhere (Qt.Popup flag handles ESC and outside-click).

- Store help text in self._help_text instead of setToolTip()
- Add _toggle_help_popup() method: creates/destroys floating QFrame
- Update test to check _help_text attribute instead of toolTip()

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
thanhnv
2026-09-08 10:08:15 +09:00
co-authored by Claude Opus 5
parent 42f4a058ea
commit 0cb6035863
2 changed files with 55 additions and 17 deletions
+6 -5
View File
@@ -51,15 +51,16 @@ def test_help_icon_exists(dialog):
def test_help_icon_has_tooltip(dialog):
"""Help icon must have a non-empty tooltip with both Project ID and Jira Key explanations."""
"""Help icon must store help text with both Project ID and Jira Key explanations."""
from PySide6.QtWidgets import QToolButton
dlg = dialog
help_icons = dlg.findChildren(QToolButton)
assert help_icons, "No help button found"
tooltip = help_icons[0].toolTip()
assert tooltip, "Help button has no tooltip"
assert "Project ID" in tooltip, "Tooltip missing Project ID explanation"
assert "Jira Key" in tooltip, "Tooltip missing Jira Key explanation"
# Help text is stored in _help_text for click-based popup
help_text = getattr(dlg, '_help_text', '') or help_icons[0].toolTip()
assert help_text, "Help button has no help content"
assert "Project ID" in help_text, "Help content missing Project ID explanation"
assert "Jira Key" in help_text, "Help content missing Jira Key explanation"
# ---- Help text content ----------------------------------------------------
+49 -12
View File
@@ -11,12 +11,12 @@ setup dialog; OneDrive/SharePoint: neither, they only toggle).
"""
from __future__ import annotations
from PySide6.QtCore import Qt
from PySide6.QtCore import Qt, QPoint
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QCheckBox, QDialog, QFormLayout, QFrame, QGroupBox, QHBoxLayout, QLabel,
QLineEdit, QMessageBox, QPushButton, QScrollArea, QToolButton, QToolTip,
QVBoxLayout, QWidget,
QLineEdit, QMessageBox, QPushButton, QScrollArea, QToolButton,
QVBoxLayout, QWidget, QApplication,
)
from ..core.ext_connectors import CATEGORIES as EXT_CATEGORIES
@@ -109,12 +109,6 @@ class JiraConnectDialog(QDialog):
mapping_label = QLabel(tr("connectors.jira_kb_mapping_label"))
self.help_icon = QToolButton()
self.help_icon.setText("?")
self.help_icon.setToolTip(
"<b>" + tr("connectors.jira_kb_project_id_title") + "</b><br>"
+ tr("connectors.jira_kb_project_id_help")
+ "<br><br><b>" + tr("connectors.jira_kb_jira_key_title") + "</b><br>"
+ tr("connectors.jira_kb_jira_key_help")
)
self.help_icon.setStyleSheet("""
QToolButton {
border: 1px solid #5B9BD5;
@@ -135,9 +129,15 @@ class JiraConnectDialog(QDialog):
color: white;
}
""")
# Native Qt tooltip: hover to show, no click handler needed.
# AutoRaise=False keeps the button always visible (not faded out).
self.help_icon.setAutoRaise(False)
# Click-based popover: build help content once, show on click
self._help_text = (
"<b>" + tr("connectors.jira_kb_project_id_title") + "</b><br>"
+ tr("connectors.jira_kb_project_id_help")
+ "<br><br><b>" + tr("connectors.jira_kb_jira_key_title") + "</b><br>"
+ tr("connectors.jira_kb_jira_key_help")
)
self._help_popup = None
self.help_icon.clicked.connect(self._toggle_help_popup)
label_row = QHBoxLayout()
label_row.setSpacing(4)
label_row.addWidget(mapping_label)
@@ -188,6 +188,43 @@ class JiraConnectDialog(QDialog):
self.kb_enabled.toggled.connect(self._update_sync_state)
self._update_sync_state(self.kb_enabled.isChecked())
def _toggle_help_popup(self) -> None:
"""Show/hide a floating help popup when the ? button is clicked."""
if self._help_popup is not None and self._help_popup.isVisible():
self._help_popup.hide()
self._help_popup.deleteLater()
self._help_popup = None
return
popup = QFrame(self)
popup.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint)
popup.setAttribute(Qt.WA_DeleteOnClose, False)
popup.setStyleSheet("""
QFrame {
background: #2D2D2D;
border: 1px solid #5B9BD5;
border-radius: 8px;
padding: 12px;
}
""")
popup_layout = QVBoxLayout(popup)
popup_layout.setContentsMargins(12, 10, 12, 10)
content = QLabel(self._help_text)
content.setWordWrap(True)
content.setMaximumWidth(380)
content.setStyleSheet("color: #E0E0E0; font-size: 12px; background: transparent; border: none;")
content.setTextFormat(Qt.RichText)
content.setOpenExternalLinks(True)
popup_layout.addWidget(content)
# Position below the help button
btn_global = self.help_icon.mapToGlobal(QPoint(0, self.help_icon.height()))
popup.move(btn_global)
popup.show()
popup.raise_()
self._help_popup = popup
def _on_paste(self, text: str) -> None:
"""Auto-fill Base URL from a pasted Jira link."""
import re