Files
sshclient/ui/snippet_dialog.py
Your Name 2b29a5cf48 feat: command snippets + UI test coverage for new features
- core/snippets.py: SnippetManager with 20 prebuilt sysadmin commands,
  CRUD + reorder, persisted to ~/.sshclient/snippets.json
- ui/snippet_dialog.py: SnippetDialog (add/edit) + SnippetManagerDialog
  (table view with add/edit/delete/move up/down)
- ui/terminal_panel.py: snippet combo box in toolbar, send_command()
  method to inject commands into interactive shell, snippet manager button
- README.md: updated feature table, usage section, project structure
- test_ui.py: added [2/4] checks for sparkline/snippets/theme,
  added [4/4] theme toggle verification
2026-07-28 23:03:37 +08:00

152 lines
5.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
命令片段管理对话框
"""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem,
QPushButton, QLabel, QLineEdit, QTextEdit, QMessageBox, QHeaderView,
QAbstractItemView, QSplitter, QWidget, QFormLayout,
)
from core.snippets import SnippetManager
class SnippetDialog(QDialog):
"""单个片段的编辑/新增对话框"""
def __init__(self, parent=None, name: str = "", cmd: str = ""):
super().__init__(parent)
self.setWindowTitle("编辑片段" if name else "新增片段")
self.setMinimumWidth(460)
v = QVBoxLayout(self)
form = QFormLayout()
self.name_edit = QLineEdit(name)
self.name_edit.setPlaceholderText("如:查看端口占用")
form.addRow("名称:", self.name_edit)
self.cmd_edit = QTextEdit(cmd)
self.cmd_edit.setPlaceholderText("如:ss -tlnp | grep :80")
self.cmd_edit.setMaximumHeight(80)
form.addRow("命令:", self.cmd_edit)
v.addLayout(form)
btns = QHBoxLayout()
btns.addStretch(1)
ok = QPushButton("保存")
ok.clicked.connect(self._on_ok)
cancel = QPushButton("取消")
cancel.clicked.connect(self.reject)
btns.addWidget(ok)
btns.addWidget(cancel)
v.addLayout(btns)
def _on_ok(self):
if not self.name_edit.text().strip():
QMessageBox.warning(self, "提示", "请输入名称")
return
if not self.cmd_edit.toPlainText().strip():
QMessageBox.warning(self, "提示", "请输入命令")
return
self.accept()
def get_value(self) -> dict:
return {
"name": self.name_edit.text().strip(),
"cmd": self.cmd_edit.toPlainText().strip(),
}
class SnippetManagerDialog(QDialog):
"""片段管理主对话框:表格 + 增删改 + 上下移"""
def __init__(self, mgr: SnippetManager, parent=None):
super().__init__(parent)
self.mgr = mgr
self.setWindowTitle("命令片段管理")
self.setMinimumSize(520, 420)
self._build_ui()
self._refresh_table()
def _build_ui(self):
v = QVBoxLayout(self)
# 工具栏
toolbar = QHBoxLayout()
toolbar.addWidget(QLabel("📋 命令片段列表"))
toolbar.addStretch(1)
self.btn_add = QPushButton(" 新增")
self.btn_add.clicked.connect(self._add)
self.btn_edit = QPushButton("✏ 编辑")
self.btn_edit.clicked.connect(self._edit)
self.btn_del = QPushButton("🗑 删除")
self.btn_del.clicked.connect(self._delete)
self.btn_up = QPushButton("⬆ 上移")
self.btn_up.clicked.connect(lambda: self._move(-1))
self.btn_down = QPushButton("⬇ 下移")
self.btn_down.clicked.connect(lambda: self._move(1))
for b in (self.btn_add, self.btn_edit, self.btn_del, self.btn_up, self.btn_down):
toolbar.addWidget(b)
v.addLayout(toolbar)
# 表格
self.table = QTableWidget(0, 2)
self.table.setHorizontalHeaderLabels(["名称", "命令"])
self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.table.doubleClicked.connect(self._edit)
v.addWidget(self.table)
# 关闭按钮
btns = QHBoxLayout()
btns.addStretch(1)
close = QPushButton("关闭")
close.clicked.connect(self.accept)
btns.addWidget(close)
v.addLayout(btns)
def _refresh_table(self):
snippets = self.mgr.list_all()
self.table.setRowCount(len(snippets))
for i, s in enumerate(snippets):
self.table.setItem(i, 0, QTableWidgetItem(s["name"]))
cmd_display = s["cmd"][:60] + ("..." if len(s["cmd"]) > 60 else "")
self.table.setItem(i, 1, QTableWidgetItem(cmd_display))
self.table.item(i, 0).setToolTip(s["cmd"])
def _add(self):
dlg = SnippetDialog(self)
if dlg.exec_() == dlg.Accepted:
v = dlg.get_value()
self.mgr.add(v["name"], v["cmd"])
self._refresh_table()
def _edit(self):
row = self.table.currentRow()
if row < 0:
return
s = self.mgr.list_all()[row]
dlg = SnippetDialog(self, s["name"], s["cmd"])
if dlg.exec_() == dlg.Accepted:
v = dlg.get_value()
self.mgr.update(row, v["name"], v["cmd"])
self._refresh_table()
def _delete(self):
row = self.table.currentRow()
if row < 0:
return
s = self.mgr.list_all()[row]
if QMessageBox.question(
self, "确认删除", f"删除片段「{s['name']}」?",
QMessageBox.Yes | QMessageBox.No
) == QMessageBox.Yes:
self.mgr.remove(row)
self._refresh_table()
def _move(self, direction):
row = self.table.currentRow()
if row < 0:
return
self.mgr.move(row, direction)
new_row = row + direction
self._refresh_table()
if 0 <= new_row < self.table.rowCount():
self.table.selectRow(new_row)