feat(gui): GUI V6 G3 — câblage moteur, Configuration, licence UI, build-prep

G3-A câblage moteur réel (engine_bridge.py) : EngineSettings + NerManagers à
chargement paresseux (aucun manager à l'import), kwargs alignés CLI/V5
(make_vector_redaction=False, also_make_raster_burn=True, config_path, use_hf,
ner/gliner/camembert_manager, ogc_label) ; make_process_fn engine injectable ;
état managers not_loaded/loading/ready/unavailable, échecs optionnels tolérés.

G3-B Configuration (config_state.py + tabs/tab_config.py) : ConfigState →
EngineSettings, profils via profile_defaults (path injectable), options
raster/NER local/profil/sortie, état managers, sections admin-only via admin_mode.

G3-C Licence UI (machine_id.py + tab_about) : activation par clef
(LicenseClient.activate), bouton vérifier (check), affichage statut, aucun token
loggé, aucun appel réseau au démarrage (local_status seul).

Intégration : tab_usage exécute via le moteur réel selon ConfigState
(make_process_fn), anti double-lancement UI. app.py câble Config↔Usage↔licence.

G3-D build-prep : anonymisation_gui_v6_onefile.spec (entry V6, customtkinter +
modules gui_v6 en hiddenimports). Installateur Anonymisation.iss produit déjà la
cible Anonymisation-Setup.exe. Aucun artefact .exe commité ; build Windows à part.

Tests +14 (engine_bridge 8, config_state 6). self-test exit 0, 46 tests gui_v6,
193 tests/unit (0 régression). Moteur/V5/specs CLI intacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 10:53:47 +02:00
parent c2c40543e5
commit 23557d2cf9
11 changed files with 878 additions and 28 deletions

View File

@@ -15,8 +15,10 @@ from typing import Optional
import customtkinter as ctk
from gui_v6 import theme as theme_mod
from gui_v6.config_state import ConfigState
from gui_v6.license_client import LicenseClient, LicenseStatus
from gui_v6.tabs.tab_about import AboutTab
from gui_v6.tabs.tab_config import ConfigTab
from gui_v6.tabs.tab_usage import UsageTab
_TABS = ("Utilisation", "Configuration", "À propos")
@@ -39,6 +41,9 @@ class AnonymisationApp(ctk.CTk):
self._license_client = license_client or LicenseClient("http://localhost")
status = self._safe_local_status()
# État de configuration partagé entre Configuration et Utilisation.
self._config = ConfigState()
self.title("Pseudonymisation de vos documents")
self.geometry("960x640")
@@ -78,20 +83,22 @@ class AnonymisationApp(ctk.CTk):
for name in _TABS:
tabview.add(name)
self._usage = UsageTab(tabview.tab("Utilisation"))
self._config_tab = ConfigTab(tabview.tab("Configuration"), state=self._config)
self._config_tab.pack(fill="both", expand=True)
self._usage = UsageTab(
tabview.tab("Utilisation"), config_provider=lambda: self._config
)
self._usage.pack(fill="both", expand=True)
self._about = AboutTab(
tabview.tab("À propos"), status=status, theme_name=self._theme_name
tabview.tab("À propos"),
status=status,
theme_name=self._theme_name,
license_client=self._license_client,
)
self._about.pack(fill="both", expand=True)
# Placeholder G3.
ctk.CTkLabel(
tabview.tab("Configuration"),
text="Onglet Configuration — disponible au lot G3.",
).pack(padx=16, pady=16, anchor="w")
@staticmethod
def _banner_text(status: LicenseStatus) -> str:
return f"Licence : {status.status}"