"""Snippets de commandes : bibliotheque organisee par categories, utilisable depuis un terminal (inserer sans executer, executer, executer avec Multi-Send).""" from __future__ import annotations import uuid from dataclasses import asdict, dataclass, field from pathlib import Path from app.paths import DATA_DIR from app.storage.json_store import load_json_document, save_json_document SNIPPETS_FILE = DATA_DIR / "snippets.json" SCHEMA_VERSION = 1 @dataclass class Snippet: id: str = field(default_factory=lambda: str(uuid.uuid4())) name: str = "" category: str = "" description: str = "" command: str = "" def to_dict(self) -> dict: return asdict(self) @staticmethod def from_dict(data: dict) -> Snippet: s = Snippet() for k in Snippet.__dataclass_fields__: if k in data: setattr(s, k, data[k]) return s # Quelques exemples fournis d'origine (premier lancement uniquement) : l'utilisateur # peut les modifier ou les supprimer librement, ce ne sont que des points de depart. DEFAULT_SNIPPETS: list[Snippet] = [ Snippet(name="Disk Usage", category="Linux", description="Espace disque par systeme de fichiers", command="df -h"), Snippet(name="Failed Services", category="Linux", description="Services systemd en echec", command="systemctl --failed"), Snippet(name="Listening Ports", category="Linux", description="Ports en ecoute", command="ss -tulpn"), Snippet(name="Containers", category="Docker", description="Conteneurs (tous statuts)", command="docker ps -a"), Snippet(name="Docker Cleanup", category="Docker", description="Nettoyer images/conteneurs/volumes inutilises", command="docker system prune -a"), Snippet(name="Logs", category="Docker", description="Logs d'un conteneur (a completer avec son nom)", command="docker logs -f "), Snippet(name="Cluster Status", category="Proxmox", description="Etat du cluster Proxmox", command="pvecm status"), Snippet(name="VM List", category="Proxmox", description="Liste des machines virtuelles", command="qm list"), ] class SnippetStore: """Charge/sauvegarde la liste des snippets depuis data/snippets.json.""" def __init__(self, path: Path = SNIPPETS_FILE): self.path = path self.snippets: list[Snippet] = [] self.load_warning: str | None = None self.load() def load(self) -> None: was_missing = not self.path.exists() document, warning = load_json_document( self.path, default={"schema_version": SCHEMA_VERSION, "snippets": [s.to_dict() for s in DEFAULT_SNIPPETS]}, current_version=SCHEMA_VERSION, ) self.load_warning = warning self.snippets = [Snippet.from_dict(s) for s in document.get("snippets", [])] if was_missing: self.save() def save(self) -> None: payload = {"schema_version": SCHEMA_VERSION, "snippets": [s.to_dict() for s in self.snippets]} save_json_document(self.path, payload) def get(self, snippet_id: str) -> Snippet | None: return next((s for s in self.snippets if s.id == snippet_id), None) def add(self, snippet: Snippet) -> None: self.snippets.append(snippet) self.save() def update(self, snippet: Snippet) -> None: for i, s in enumerate(self.snippets): if s.id == snippet.id: self.snippets[i] = snippet break self.save() def delete(self, snippet_id: str) -> None: self.snippets = [s for s in self.snippets if s.id != snippet_id] self.save() def categories(self) -> list[str]: return sorted({s.category for s in self.snippets if s.category}) def by_category(self) -> dict[str, list[Snippet]]: grouped: dict[str, list[Snippet]] = {} for s in sorted(self.snippets, key=lambda s: s.name.lower()): grouped.setdefault(s.category or "Sans categorie", []).append(s) return dict(sorted(grouped.items(), key=lambda kv: kv[0].lower())) def search(self, query: str) -> list[Snippet]: q = query.lower().strip() if not q: return list(self.snippets) return [ s for s in self.snippets if q in s.name.lower() or q in s.category.lower() or q in s.description.lower() or q in s.command.lower() ]