@@ -116,15 +116,15 @@ def _apply_themed_icon(widget: QPushButton, icon_name: str, size: int = 18) -> N
116116# Constantes
117117# ---------------------------------------------------------------------------
118118
119- # phase_score → (display_name, min_priority, max_priority )
120- SECTION_PHASES : dict [int , tuple [str , int , int ]] = {
121- 0 : ("Nettoyage" , 0 , 9 ),
122- 10 : ("Validation" , 10 , 19 ),
123- 20 : ("Préparation" , 20 , 29 ),
124- 30 : ("Conformité" , 30 , 39 ),
125- 40 : ("Linting" , 40 , 49 ),
126- 50 : ("Obfuscation" , 50 , 59 ),
127- 100 : ("Défaut" , 60 , 199 ),
119+ # phase_score → (display_name, description )
120+ SECTION_PHASES : dict [int , tuple [str , str ]] = {
121+ 0 : ("Nettoyage" , "Nettoyage et hygiène du workspace" ),
122+ 10 : ("Validation" , "Validation et vérification des prérequis" ),
123+ 20 : ("Préparation" , "Préparation et génération des ressources" ),
124+ 30 : ("Conformité" , "Conformité et injection de headers" ),
125+ 40 : ("Linting" , "Linting, formatage et vérification de type" ),
126+ 50 : ("Obfuscation" , "Obfuscation, protection et transpilation" ),
127+ 100 : ("Défaut" , "Autres actions (phase par défaut)" ),
128128}
129129
130130# Tag → score de phase
@@ -141,16 +141,16 @@ def _phase_score_for_tags(tags: list[str]) -> int:
141141 return min (scores ) if scores else 100
142142
143143
144- def _section_for_phase (score : int ) -> tuple [int , str , int , int ]:
145- """Retourne (key, name, min_prio, max_prio ) pour un score de phase."""
144+ def _section_for_phase (score : int ) -> tuple [int , str ]:
145+ """Retourne (key, name) pour un score de phase."""
146146 # Trouver la section dont le score correspond
147147 for key in sorted (SECTION_PHASES ):
148148 if score == key :
149- name , lo , hi = SECTION_PHASES [key ]
150- return key , name , lo , hi
149+ name , _ = SECTION_PHASES [key ]
150+ return key , name
151151 # Section par défaut
152- name , lo , hi = SECTION_PHASES [100 ]
153- return 100 , name , lo , hi
152+ name , _ = SECTION_PHASES [100 ]
153+ return 100 , name
154154
155155
156156# ---------------------------------------------------------------------------
@@ -204,25 +204,17 @@ class _PluginRow(QFrame):
204204 sig_move_up = Signal (str ) # plugin_id
205205 sig_move_down = Signal (str )
206206 sig_enabled = Signal (str , bool )
207- sig_priority = Signal (str , int )
208207
209208 def __init__ (
210209 self ,
211210 pid : str ,
212211 name : str ,
213- priority : int ,
214212 enabled : bool ,
215- min_prio : int ,
216- max_prio : int ,
217- expert_ref : "list[bool]" ,
218213 config : Optional [dict ] = None ,
219214 parent : Optional [QWidget ] = None ,
220215 ) -> None :
221216 super ().__init__ (parent )
222217 self .pid = pid
223- self ._min = min_prio
224- self ._max = max_prio
225- self ._expert_ref = expert_ref # [bool] mutable reference
226218 self .config : dict [str , Any ] = dict (config or {})
227219 self ._on_save_cb = None
228220
@@ -240,28 +232,11 @@ def __init__(
240232 self .chk .toggled .connect (lambda v : self .sig_enabled .emit (self .pid , v ))
241233 row .addWidget (self .chk )
242234
243- # Icône warning
244- self .lbl_warn = QLabel ("⚠️" )
245- self .lbl_warn .setFixedWidth (24 )
246- self .lbl_warn .setVisible (False )
247- row .addWidget (self .lbl_warn )
248-
249235 # Nom plugin
250236 self .lbl_name = QLabel (name or pid )
251237 self .lbl_name .setSizePolicy (QSizePolicy .Expanding , QSizePolicy .Preferred )
252238 row .addWidget (self .lbl_name )
253239
254- # Label "priority"
255- row .addWidget (QLabel ("priority" ))
256-
257- # Spinbox priorité
258- self .spin = QSpinBox ()
259- self .spin .setRange (0 , 999 )
260- self .spin .setValue (priority )
261- self .spin .setFixedWidth (70 )
262- self .spin .valueChanged .connect (self ._on_priority_changed )
263- row .addWidget (self .spin )
264-
265240 # Boutons ↑ ↓
266241 self .btn_up = QPushButton ()
267242 self .btn_up .setFixedWidth (32 )
@@ -277,62 +252,22 @@ def __init__(
277252 self .btn_down .clicked .connect (lambda : self .sig_move_down .emit (self .pid ))
278253 row .addWidget (self .btn_down )
279254
280- self ._refresh_warning ( )
255+ self .setStyleSheet ( "QFrame#PluginRow { background: transparent; border: none; }" )
281256
282257 # ------------------------------------------------------------------
283258
284- def _on_priority_changed (self , val : int ) -> None :
285- self ._refresh_warning ()
286- self .sig_priority .emit (self .pid , val )
287-
288- def _refresh_warning (self ) -> None :
289- """Met à jour l'indicateur ⚠️ et les styles selon expert mode et valeur."""
290- expert = bool (self ._expert_ref [0 ]) if self ._expert_ref else False
291- val = self .spin .value ()
292- out_of_range = not (self ._min <= val <= self ._max )
293-
294- if expert or not out_of_range :
295- self .lbl_warn .setVisible (False )
296- # Utilise un fond transparent pour laisser voir le fond de la section
297- self .setStyleSheet ("QFrame#PluginRow { background: transparent; border: none; }" )
298- self .spin .setStyleSheet ("" )
299- else :
300- self .lbl_warn .setVisible (True )
301- self .lbl_warn .setToolTip (
302- f"⚠️ Priorité { val } hors de la plage recommandée ({ self ._min } -{ self ._max } ).\n "
303- "L'ordre d'exécution peut être inattendu.\n "
304- "Utilisez le mode Expert pour désactiver les avertissements."
305- )
306- colors = _get_bcasl_colors ()
307- self .setStyleSheet (f"QFrame#PluginRow {{ background: { colors ['warn_bg' ]} ; border: 1px solid { colors ['warn_border' ]} ; border-radius: 4px; }}" )
308- self .spin .setStyleSheet (f"QSpinBox {{ border: 2px solid { colors ['warn_border' ]} ; }}" )
309-
310- def refresh_expert (self ) -> None :
311- """Appelé quand expert mode change."""
312- expert = bool (self ._expert_ref [0 ]) if self ._expert_ref else False
313- if expert :
314- self .spin .setRange (0 , 999 )
315- else :
316- self .spin .setRange (0 , 999 ) # toujours libre en saisie, warning géré visuellement
317- self ._refresh_warning ()
318-
319259 # ------------------------------------------------------------------
320260 # Accesseurs
321261
322262 @property
323263 def is_enabled (self ) -> bool :
324264 return self .chk .isChecked ()
325265
326- @property
327- def priority_value (self ) -> int :
328- return self .spin .value ()
329-
330266 def snapshot (self ) -> dict [str , Any ]:
331- return {"pid" : self .pid , "enabled" : self .is_enabled , "priority" : self . priority_value }
267+ return {"pid" : self .pid , "enabled" : self .is_enabled }
332268
333269 def restore (self , snap : dict [str , Any ]) -> None :
334270 self .chk .setChecked (bool (snap .get ("enabled" , True )))
335- self .spin .setValue (int (snap .get ("priority" , 0 )))
336271
337272
338273# ---------------------------------------------------------------------------
@@ -348,21 +283,15 @@ def __init__(
348283 self ,
349284 phase_key : int ,
350285 name : str ,
351- min_prio : int ,
352- max_prio : int ,
353- expert_ref : "list[bool]" ,
354286 parent : Optional [QWidget ] = None ,
355287 ) -> None :
356288 super ().__init__ (parent )
357289 self .phase_key = phase_key
358290 self ._name = name
359- self ._min = min_prio
360- self ._max = max_prio
361- self ._expert_ref = expert_ref
362291 self ._rows : list [_PluginRow ] = []
363292
364293 # Titre natif du GroupBox
365- self .setTitle (f" { name } ( { min_prio } – { max_prio } )" )
294+ self .setTitle (name )
366295
367296 # Rendre le GroupBox collapsible via la checkbox native
368297 self .setCheckable (True )
@@ -388,7 +317,6 @@ def add_row(self, row: _PluginRow) -> None:
388317 row .sig_move_up .connect (self ._on_move_up )
389318 row .sig_move_down .connect (self ._on_move_down )
390319 row .sig_enabled .connect (lambda _pid , _v : self .sig_changed .emit ())
391- row .sig_priority .connect (lambda _pid , _v : self .sig_changed .emit ())
392320 # S'assurer que la visibilité suit l'état actuel du toggle
393321 row .setVisible (self .isChecked ())
394322 # Mettre à jour l'état des boutons ↑/↓ pour toute la section
@@ -496,9 +424,6 @@ def __init__(
496424 except Exception :
497425 self ._ark_cfg = {}
498426
499- # Expert mode : liste mutable partagée avec les rows
500- self ._expert : list [bool ] = [False ]
501-
502427 # Undo / Redo stacks
503428 self ._undo_stack : list [Any ] = []
504429 self ._redo_stack : list [Any ] = []
@@ -575,10 +500,6 @@ def _build_ui(self) -> None:
575500
576501 # Barre du bas
577502 bottom = QHBoxLayout ()
578- self ._chk_expert = QCheckBox (self ._gui .tr ("Mode Expert (priorités libres)" , "Expert mode (any priority)" ))
579- self ._chk_expert .setChecked (False )
580- self ._chk_expert .toggled .connect (self ._on_expert_toggled )
581- bottom .addWidget (self ._chk_expert )
582503 bottom .addStretch (1 )
583504
584505 btn_cancel = QPushButton (self ._gui .tr ("Annuler" , "Cancel" ))
@@ -610,6 +531,11 @@ def _populate_sections(self) -> None:
610531 plugins_raw = self ._cfg .get ("plugins" , {}) if isinstance (self ._cfg , dict ) else {}
611532 plugin_list = _read_plugin_list (plugins_raw )
612533
534+ # Charger l'état des phases
535+ phases_cfg = self ._cfg .get ("phases" , {})
536+ if not isinstance (phases_cfg , dict ):
537+ phases_cfg = {}
538+
613539 # Construire un mapping pid → entry
614540 pid_entry : dict [str , dict [str , Any ]] = {}
615541 for entry in plugin_list :
@@ -629,7 +555,7 @@ def _populate_sections(self) -> None:
629555 score = _phase_score_for_tags (list (tags ))
630556 phase_groups .setdefault (score , []).append ((pid , entry ))
631557
632- # Trier chaque groupe par priorité
558+ # Trier chaque groupe par priorité (ordre initial)
633559 for score in phase_groups :
634560 phase_groups [score ].sort (key = lambda x : int (x [1 ].get ("priority" , 0 )))
635561
@@ -640,10 +566,15 @@ def _populate_sections(self) -> None:
640566 for score in sorted (SECTION_PHASES .keys ()):
641567 if score not in phase_groups :
642568 continue
643- key_name , lo , hi = SECTION_PHASES [score ]
644- section = _SectionWidget (score , key_name , lo , hi , self ._expert )
569+ key_name , desc = SECTION_PHASES [score ]
570+ section = _SectionWidget (score , key_name )
571+ section .setToolTip (desc )
645572 section .sig_changed .connect (self ._on_any_change )
646573
574+ # Appliquer l'état d'activation de la phase
575+ if key_name in phases_cfg :
576+ section .setChecked (bool (phases_cfg [key_name ]))
577+
647578 for pid , entry in phase_groups [score ]:
648579 meta = self ._meta_map .get (pid , {})
649580 display_name = meta .get ("name" ) or pid
@@ -652,11 +583,7 @@ def _populate_sections(self) -> None:
652583 row = _PluginRow (
653584 pid = pid ,
654585 name = label ,
655- priority = int (entry .get ("priority" , 0 )),
656586 enabled = bool (entry .get ("enabled" , True )),
657- min_prio = lo ,
658- max_prio = hi ,
659- expert_ref = self ._expert ,
660587 config = dict (entry .get ("config" , {})),
661588 )
662589 section .add_row (row )
@@ -813,21 +740,30 @@ def _do_save(self) -> None:
813740 f"Impossible de mettre à jour ark.yml: { e } "
814741 )
815742
816- # 2) Construire la liste ordonnée de plugins pour bcasl.yml
743+ # 2) Construire la liste ordonnée de plugins pour bcasl.yml et l'état des phases
817744 ordered : list [dict [str , Any ]] = []
745+ phases_state : dict [str , bool ] = {}
746+
747+ # Le backend utilise rec.priority pour ordonner dans une phase.
748+ # On assigne un index global incrémental pour refléter l'ordre visuel.
749+ current_prio = 0
750+
818751 for section in self ._sections :
752+ phases_state [section ._name ] = section .isChecked ()
819753 for row in section .rows :
820754 cfg_for_row = plugin_configs .get (row .pid , row .config or {})
821755 ordered .append ({
822756 "name" : row .pid ,
823757 "enabled" : row .is_enabled ,
824- "priority" : row . priority_value ,
758+ "priority" : current_prio ,
825759 "config" : cfg_for_row ,
826760 })
761+ current_prio += 1
827762
828763 # Construire la config de sortie pour bcasl.yml
829764 cfg_out : dict [str , Any ] = dict (self ._cfg ) if isinstance (self ._cfg , dict ) else {}
830765 cfg_out ["plugins" ] = _plugins_list_to_yaml (ordered )
766+ cfg_out ["phases" ] = phases_state
831767 # plugin_order maintient la compatibilité avec l'ancien loader
832768 cfg_out ["plugin_order" ] = [e ["name" ] for e in ordered ]
833769
0 commit comments