Suite des retours Dom sur la GUI V6 (par-dessus 6a0a581).
Addendum Profils / Réglages :
- Nouveau sous-onglet Administration « 👤 Profils » : le profil actif devient
un objet lisible (nom, description, masque requis, template, listes locales
avec compteurs) — données réelles lues depuis profile_defaults.
- Fenêtre « Tableau des termes » (terms_table_window.py) : table scrollable
avec recherche/filtre, colonnes Type/Terme/Source ; reste lisible à 50+
termes. Ajouter/éditer/supprimer désactivés « (à venir) » (écriture par
profil non câblée).
- Réglages : « Profil métier » → « Profil d'anonymisation », « Sortie… » →
« Dossier de sortie… » (+ infobulle), hints moteurs (standard/optionnel/
plus lent), bouton « Voir le profil », « Ouvrir le tableau des termes ».
- Aide « ? » + infobulles (ui_kit.attach_tooltip) près des éléments ambigus.
- profile_view.py : logique pure (résumé profil + lignes du tableau),
testable sans display.
Addendum bêta : en-tête « aivanonym » + badge « bêta », titre fenêtre
« … — bêta ». Détail version conservé dans À propos.
tests/unit/test_gui_v6_profiles.py + ajouts shell. 237 tests unit OK
(228 → 237, 0 régression), self-test GUI V6 OK, navigation des 5 sous-onglets
+ thème OK. V5/moteur/app_aivanov/profile_defaults non touchés, 0 dépendance.
Aucun build/push sans GO Dom — validation visuelle Dom attendue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
115 lines
4.6 KiB
Python
115 lines
4.6 KiB
Python
"""Fenêtre « Tableau des termes » d'un profil (lisible même avec 50+ termes).
|
|
|
|
Table scrollable avec recherche/filtre — colonnes Type / Terme / Source (profil).
|
|
Lecture seule pour l'instant : ajouter/supprimer/éditer sont désactivés et
|
|
marqués « (à venir) » (l'écriture par profil n'est pas encore câblée).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tkinter as tk
|
|
from typing import Optional
|
|
|
|
import customtkinter as ctk
|
|
|
|
from gui_v6 import ui_kit
|
|
from gui_v6.profile_view import filter_term_rows
|
|
|
|
_TYPE_COLORS = {
|
|
"À conserver": "success",
|
|
"À masquer": "primary",
|
|
"À ignorer": "text_muted",
|
|
}
|
|
|
|
|
|
class TermsTableWindow(ctk.CTkToplevel):
|
|
def __init__(
|
|
self,
|
|
master,
|
|
palette: dict,
|
|
rows,
|
|
*,
|
|
title: str = "Tableau des termes",
|
|
profile_label: str = "",
|
|
) -> None:
|
|
super().__init__(master)
|
|
self._palette = palette
|
|
self._rows = list(rows)
|
|
self._profile_label = profile_label
|
|
self._visible = list(self._rows)
|
|
|
|
self.title(title)
|
|
self.geometry("740x560")
|
|
self.minsize(520, 360)
|
|
try:
|
|
self.configure(fg_color=palette["bg"])
|
|
except Exception:
|
|
pass
|
|
|
|
self._query = tk.StringVar()
|
|
self._count_text = tk.StringVar(value="")
|
|
self._build()
|
|
self._refresh()
|
|
try:
|
|
self.transient(master)
|
|
self.after(120, lambda: (self.lift(), self.focus_force()))
|
|
except Exception:
|
|
pass
|
|
|
|
# -- coutures testables --------------------------------------------------
|
|
def set_query(self, query: str) -> None:
|
|
self._query.set(query)
|
|
self._refresh()
|
|
|
|
def visible_count(self) -> int:
|
|
return len(self._visible)
|
|
|
|
def add_is_disabled(self) -> bool:
|
|
return str(self._add_btn.cget("state")) == "disabled"
|
|
|
|
# -- UI ------------------------------------------------------------------
|
|
def _build(self) -> None:
|
|
p = self._palette
|
|
head = ctk.CTkFrame(self, fg_color="transparent")
|
|
head.pack(fill="x", padx=12, pady=(12, 4))
|
|
title = "Termes du profil"
|
|
if self._profile_label:
|
|
title += f" « {self._profile_label} »"
|
|
ctk.CTkLabel(head, text=title, text_color=p["text"], font=ui_kit.font(15, "bold")).pack(side="left")
|
|
|
|
bar = ctk.CTkFrame(self, fg_color="transparent")
|
|
bar.pack(fill="x", padx=12, pady=(0, 6))
|
|
ctk.CTkLabel(bar, text="🔎 Rechercher :", text_color=p["text_dim"], font=ui_kit.font(12)).pack(side="left")
|
|
entry = ctk.CTkEntry(bar, textvariable=self._query, width=240)
|
|
entry.pack(side="left", padx=6)
|
|
self._query.trace_add("write", lambda *_: self._refresh())
|
|
self._add_btn = ui_kit.secondary_button(bar, p, "+ Ajouter (à venir)", command=lambda: None)
|
|
self._add_btn.configure(state="disabled")
|
|
self._add_btn.pack(side="right")
|
|
|
|
header = ctk.CTkFrame(self, fg_color=p["card"], corner_radius=6)
|
|
header.pack(fill="x", padx=12)
|
|
for text, width in [("TYPE", 130), ("TERME", 360), ("SOURCE (PROFIL)", 180)]:
|
|
ctk.CTkLabel(header, text=text, width=width, anchor="w", text_color=p["text_muted"], font=ui_kit.font(10, "bold")).pack(side="left", padx=8, pady=4)
|
|
|
|
self._table = ctk.CTkScrollableFrame(self, fg_color=p["bg"])
|
|
self._table.pack(fill="both", expand=True, padx=12, pady=(2, 4))
|
|
|
|
ctk.CTkLabel(self, textvariable=self._count_text, text_color=p["text_muted"], font=ui_kit.font(11), anchor="w").pack(fill="x", padx=14, pady=(0, 10))
|
|
|
|
def _refresh(self) -> None:
|
|
p = self._palette
|
|
self._visible = filter_term_rows(self._rows, self._query.get())
|
|
for child in self._table.winfo_children():
|
|
child.destroy()
|
|
if not self._visible:
|
|
ctk.CTkLabel(self._table, text="Aucun terme.", text_color=p["text_muted"], font=ui_kit.font(12)).pack(anchor="w", padx=8, pady=8)
|
|
for type_label, term, source in self._visible:
|
|
row = ctk.CTkFrame(self._table, fg_color="transparent")
|
|
row.pack(fill="x", pady=1)
|
|
color = p[_TYPE_COLORS.get(type_label, "text")]
|
|
ctk.CTkLabel(row, text=type_label, width=130, anchor="w", text_color=color, font=ui_kit.font(11, "bold")).pack(side="left", padx=8)
|
|
ctk.CTkLabel(row, text=term, width=360, anchor="w", text_color=p["text"], font=ui_kit.font(12)).pack(side="left", padx=8)
|
|
ctk.CTkLabel(row, text=source, width=180, anchor="w", text_color=p["text_muted"], font=ui_kit.font(11)).pack(side="left", padx=8)
|
|
self._count_text.set(f"{len(self._visible)} terme(s) affiché(s) sur {len(self._rows)}.")
|