summaryrefslogtreecommitdiffstats
path: root/ui/git_view.py
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-05-03 10:42:30 +0200
committerDanilo M. <danix@danix.xyz>2026-05-03 10:42:30 +0200
commit8263e7374d2c81ed0a64481a978d6e7157016b08 (patch)
tree977c3f46ae4b0f25a2f449b86faa12889e38ba63 /ui/git_view.py
parent1786c672753a74b876f415dd5f32742c0e24f8c9 (diff)
downloadpublisher-8263e7374d2c81ed0a64481a978d6e7157016b08.tar.gz
publisher-8263e7374d2c81ed0a64481a978d6e7157016b08.zip
feat: git view with status, pull/push, and deleted article restore
Diffstat (limited to 'ui/git_view.py')
-rw-r--r--ui/git_view.py134
1 files changed, 134 insertions, 0 deletions
diff --git a/ui/git_view.py b/ui/git_view.py
new file mode 100644
index 0000000..2c759e8
--- /dev/null
+++ b/ui/git_view.py
@@ -0,0 +1,134 @@
+from __future__ import annotations
+from pathlib import Path
+from PyQt6.QtWidgets import (
+ QWidget, QVBoxLayout, QHBoxLayout, QLabel,
+ QPushButton, QPlainTextEdit, QTabWidget, QListWidget, QListWidgetItem,
+)
+from PyQt6.QtCore import pyqtSignal
+from workers.git_worker import GitWorker
+import subprocess
+
+class GitView(QWidget):
+ refresh_needed = pyqtSignal()
+
+ def __init__(self, repo_path: Path, parent=None):
+ super().__init__(parent)
+ self._repo_path = repo_path
+ self._worker: GitWorker | None = None
+ self._build_ui()
+
+ def _build_ui(self):
+ layout = QVBoxLayout(self)
+
+ status_row = QHBoxLayout()
+ self._branch_label = QLabel("Branch: —")
+ self._branch_label.setStyleSheet("color:#a855f7;font-weight:bold;")
+ status_row.addWidget(self._branch_label)
+ status_row.addStretch()
+ refresh_btn = QPushButton("🔄 Refresh")
+ refresh_btn.clicked.connect(self.load_status)
+ status_row.addWidget(refresh_btn)
+ layout.addLayout(status_row)
+
+ tabs = QTabWidget()
+
+ status_tab = QWidget()
+ st_layout = QVBoxLayout(status_tab)
+ self._status_log = QPlainTextEdit()
+ self._status_log.setReadOnly(True)
+ self._status_log.setStyleSheet("background:#0a0a12;color:#ccc;font-family:monospace;font-size:11px;")
+ st_layout.addWidget(self._status_log)
+
+ btns = QHBoxLayout()
+ for label, slot in [
+ ("⬇ Pull", self._do_pull),
+ ("🧪 Push master", self._do_push_master),
+ ("🚢 Push production", self._do_push_production),
+ ]:
+ btn = QPushButton(label)
+ btn.clicked.connect(slot)
+ btns.addWidget(btn)
+ btns.addStretch()
+ st_layout.addLayout(btns)
+ tabs.addTab(status_tab, "Stato repo")
+
+ deleted_tab = QWidget()
+ del_layout = QVBoxLayout(deleted_tab)
+ del_layout.addWidget(QLabel("Articoli eliminati (da git log):"))
+ self._deleted_list = QListWidget()
+ del_layout.addWidget(self._deleted_list)
+ restore_btn = QPushButton("♻️ Ripristina selezionato")
+ restore_btn.clicked.connect(self._do_restore)
+ del_layout.addWidget(restore_btn)
+ tabs.addTab(deleted_tab, "Articoli eliminati")
+
+ layout.addWidget(tabs)
+
+ self._output = QPlainTextEdit()
+ self._output.setReadOnly(True)
+ self._output.setStyleSheet("background:#0a0a12;color:#00ff88;font-family:monospace;font-size:11px;")
+ self._output.setMaximumHeight(150)
+ layout.addWidget(self._output)
+
+ def load_status(self):
+ try:
+ branch = subprocess.check_output(
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
+ cwd=self._repo_path, text=True,
+ ).strip()
+ self._branch_label.setText(f"Branch: {branch}")
+
+ status = subprocess.check_output(
+ ["git", "status", "--short"],
+ cwd=self._repo_path, text=True,
+ )
+ log = subprocess.check_output(
+ ["git", "log", "--oneline", "-5"],
+ cwd=self._repo_path, text=True,
+ )
+ self._status_log.setPlainText(f"--- git status ---\n{status}\n--- ultimi commit ---\n{log}")
+
+ self._deleted_list.clear()
+ deleted = subprocess.check_output(
+ ["git", "log", "--diff-filter=D", "--name-only", "--pretty=format:%H %s", "--", "content/"],
+ cwd=self._repo_path, text=True,
+ )
+ current_hash = None
+ for line in deleted.splitlines():
+ if line.strip() == "":
+ continue
+ if line.startswith("content/"):
+ if current_hash:
+ item = QListWidgetItem(f"{line} [{current_hash[:8]}]")
+ item.setData(256, (current_hash, line))
+ self._deleted_list.addItem(item)
+ else:
+ parts = line.split(" ", 1)
+ current_hash = parts[0] if parts else None
+ except Exception as e:
+ self._output.appendPlainText(f"[Errore] {e}")
+
+ def _run_worker(self, worker):
+ self._worker = worker
+ worker.output.connect(self._output.appendPlainText)
+ worker.error.connect(lambda e: self._output.appendPlainText(f"[ERRORE] {e}"))
+ worker.finished.connect(lambda ok: self.refresh_needed.emit() if ok else None)
+ worker.start()
+
+ def _do_pull(self):
+ self._run_worker(GitWorker.pull(self._repo_path, self))
+
+ def _do_push_master(self):
+ self._run_worker(GitWorker.push_master(self._repo_path, self))
+
+ def _do_push_production(self):
+ self._run_worker(GitWorker.push_production(self._repo_path, self))
+
+ def _do_restore(self):
+ item = self._deleted_list.currentItem()
+ if not item:
+ return
+ commit_hash, rel_path = item.data(256)
+ worker = GitWorker.restore_article(self._repo_path, commit_hash, rel_path, self)
+ self._run_worker(worker)
+ self.load_status()