mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-08-14 01:23:46 +02:00
211 lines
7.9 KiB
Python
211 lines
7.9 KiB
Python
"""Verification results dialog shown after install/configure workflows."""
|
|
|
|
import logging
|
|
|
|
from PySide6.QtCore import Qt
|
|
from PySide6.QtGui import QClipboard, QGuiApplication
|
|
from PySide6.QtWidgets import (
|
|
QDialog, QHBoxLayout, QLabel, QPushButton,
|
|
QTextEdit, QVBoxLayout,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_COLOR_FAIL = "#e05050"
|
|
_COLOR_WARN = "#f0c040"
|
|
_COLOR_OK = "#3fd0ea"
|
|
_COLOR_DIM = "#888888"
|
|
|
|
|
|
def _html_row(prefix: str, color: str, msg: str) -> str:
|
|
safe = msg.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
return (
|
|
f'<span style="color:{color}; font-family:monospace;">'
|
|
f'<b>{prefix}</b> {safe}'
|
|
f'</span><br>'
|
|
)
|
|
|
|
|
|
class VerificationResultsDialog(QDialog):
|
|
"""Shows the output of verify_install.py after a workflow completes."""
|
|
|
|
def __init__(self, results, parent=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Installation Verification")
|
|
self.setWindowModality(Qt.NonModal)
|
|
self.setAttribute(Qt.WA_DeleteOnClose, True)
|
|
self.setMinimumWidth(600)
|
|
|
|
self._results = results
|
|
n_pass = len(results.passes)
|
|
n_warn = len(results.warnings)
|
|
n_fail = len(results.failures)
|
|
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(20, 16, 20, 16)
|
|
layout.setSpacing(10)
|
|
|
|
# --- Headline ---
|
|
if n_fail:
|
|
headline = f"[FAIL] {n_fail} failure{'s' if n_fail != 1 else ''}, {n_warn} warning{'s' if n_warn != 1 else ''}, {n_pass} passed"
|
|
h_color = _COLOR_FAIL
|
|
elif n_warn:
|
|
headline = f"[WARN] {n_warn} warning{'s' if n_warn != 1 else ''}, {n_pass} passed"
|
|
h_color = _COLOR_WARN
|
|
else:
|
|
headline = f"[OK] All {n_pass} checks passed"
|
|
h_color = _COLOR_OK
|
|
|
|
headline_label = QLabel(headline)
|
|
headline_label.setStyleSheet(
|
|
f"font-size: 14px; font-weight: bold; color: {h_color};"
|
|
)
|
|
layout.addWidget(headline_label)
|
|
|
|
# --- Issues view (always visible) ---
|
|
self._issues_view = QTextEdit()
|
|
self._issues_view.setReadOnly(True)
|
|
self._issues_view.setStyleSheet(
|
|
"QTextEdit { background: #1e1e1e; border: 1px solid #444; "
|
|
"border-radius: 4px; font-size: 12px; padding: 6px; }"
|
|
)
|
|
self._issues_view.setHtml(self._build_issues_html(results))
|
|
self._issues_view.setMinimumHeight(80)
|
|
self._issues_view.setMaximumHeight(220)
|
|
layout.addWidget(self._issues_view)
|
|
|
|
# --- Full report view (hidden by default) ---
|
|
self._full_view = QTextEdit()
|
|
self._full_view.setReadOnly(True)
|
|
self._full_view.setStyleSheet(
|
|
"QTextEdit { background: #1a1a1a; border: 1px solid #333; "
|
|
"border-radius: 4px; font-size: 11px; padding: 6px; }"
|
|
)
|
|
self._full_view.setHtml(self._build_full_html(results))
|
|
self._full_view.setMinimumHeight(160)
|
|
self._full_view.setMaximumHeight(300)
|
|
self._full_view.setVisible(False)
|
|
layout.addWidget(self._full_view)
|
|
|
|
# --- Button row ---
|
|
btn_row = QHBoxLayout()
|
|
|
|
self._toggle_btn = QPushButton("Show all checks")
|
|
self._toggle_btn.setFixedWidth(130)
|
|
self._toggle_btn.setStyleSheet(
|
|
"QPushButton { font-size: 11px; color: #ccc; background: #3a3a3a; "
|
|
"border: 1px solid #555; border-radius: 4px; padding: 4px 8px; }"
|
|
"QPushButton:hover { background: #4a4a4a; color: #fff; }"
|
|
)
|
|
self._toggle_btn.setCursor(Qt.PointingHandCursor)
|
|
self._toggle_btn.clicked.connect(self._toggle_full_report)
|
|
btn_row.addWidget(self._toggle_btn)
|
|
|
|
btn_row.addStretch()
|
|
|
|
copy_btn = QPushButton("Copy Report")
|
|
copy_btn.setFixedWidth(110)
|
|
copy_btn.setToolTip("Copy plain-text report to clipboard")
|
|
copy_btn.clicked.connect(self._copy_report)
|
|
btn_row.addWidget(copy_btn)
|
|
|
|
close_btn = QPushButton("Close")
|
|
close_btn.setFixedWidth(80)
|
|
close_btn.clicked.connect(self.accept)
|
|
btn_row.addWidget(close_btn)
|
|
|
|
layout.addLayout(btn_row)
|
|
|
|
self.adjustSize()
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
def _build_issues_html(self, results) -> str:
|
|
lines = []
|
|
for msg in results.failures:
|
|
lines.append(_html_row("[FAIL]", _COLOR_FAIL, msg))
|
|
for msg in results.warnings:
|
|
lines.append(_html_row("[WARN]", _COLOR_WARN, msg))
|
|
if not results.failures and not results.warnings:
|
|
lines.append(_html_row("[OK]", _COLOR_OK, "No issues found. Your modlist is correctly configured."))
|
|
return "".join(lines)
|
|
|
|
def _build_full_html(self, results) -> str:
|
|
lines = []
|
|
if results.failures:
|
|
lines.append(f'<span style="color:{_COLOR_DIM}; font-size:10px;">FAILURES</span><br>')
|
|
for msg in results.failures:
|
|
lines.append(_html_row("[FAIL]", _COLOR_FAIL, msg))
|
|
lines.append("<br>")
|
|
if results.warnings:
|
|
lines.append(f'<span style="color:{_COLOR_DIM}; font-size:10px;">WARNINGS</span><br>')
|
|
for msg in results.warnings:
|
|
lines.append(_html_row("[WARN]", _COLOR_WARN, msg))
|
|
lines.append("<br>")
|
|
if results.passes:
|
|
lines.append(f'<span style="color:{_COLOR_DIM}; font-size:10px;">PASSED</span><br>')
|
|
for msg in results.passes:
|
|
lines.append(_html_row("[OK] ", _COLOR_OK, msg))
|
|
components = getattr(results, "installed_components", [])
|
|
if components:
|
|
lines.append("<br>")
|
|
lines.append(f'<span style="color:{_COLOR_DIM}; font-size:10px;">INSTALLED COMPONENTS ({len(components)})</span><br>')
|
|
for c in components:
|
|
method = c.get("method", "unknown")
|
|
method_color = _COLOR_OK if method == "native" else _COLOR_DIM
|
|
safe_name = c["name"].replace("&", "&").replace("<", "<")
|
|
lines.append(
|
|
f'<span style="font-family:monospace; font-size:11px;">'
|
|
f'{safe_name}'
|
|
f' <span style="color:{method_color}; font-size:10px;">({method})</span>'
|
|
f'</span><br>'
|
|
)
|
|
return "".join(lines)
|
|
|
|
def _build_plain_text(self) -> str:
|
|
r = self._results
|
|
n_pass = len(r.passes)
|
|
n_warn = len(r.warnings)
|
|
n_fail = len(r.failures)
|
|
|
|
lines = ["Jackify - Installation Verification", "=" * 40]
|
|
if n_fail:
|
|
lines.append(f"RESULT: FAILED ({n_fail} failures, {n_warn} warnings, {n_pass} passed)")
|
|
elif n_warn:
|
|
lines.append(f"RESULT: WARNING ({n_warn} warnings, {n_pass} passed)")
|
|
else:
|
|
lines.append(f"RESULT: OK (all {n_pass} checks passed)")
|
|
lines.append("")
|
|
|
|
if r.failures:
|
|
lines.append("FAILURES:")
|
|
for msg in r.failures:
|
|
lines.append(f" [FAIL] {msg}")
|
|
lines.append("")
|
|
if r.warnings:
|
|
lines.append("WARNINGS:")
|
|
for msg in r.warnings:
|
|
lines.append(f" [WARN] {msg}")
|
|
lines.append("")
|
|
if r.passes:
|
|
lines.append("PASSED:")
|
|
for msg in r.passes:
|
|
lines.append(f" [OK] {msg}")
|
|
components = getattr(r, "installed_components", [])
|
|
if components:
|
|
lines.append("")
|
|
lines.append("INSTALLED COMPONENTS:")
|
|
for c in components:
|
|
lines.append(f" {c['name']} ({c.get('method', 'unknown')})")
|
|
|
|
return "\n".join(lines)
|
|
|
|
def _toggle_full_report(self):
|
|
visible = self._full_view.isVisible()
|
|
self._full_view.setVisible(not visible)
|
|
self._toggle_btn.setText("Hide all checks" if not visible else "Show all checks")
|
|
self.adjustSize()
|
|
|
|
def _copy_report(self):
|
|
QGuiApplication.clipboard().setText(self._build_plain_text())
|