personal workflow improvements
This commit is contained in:
1 parent
96c00fa941
commit
42a5b9778e
3 files changed
+77
-6
No files matched your search
+50
-3
@@ -25,6 +25,7 @@ from .diagnostics import collect_diagnostics
|
||||
from .batch_monitor import BatchMonitor
|
||||
from .giving_names import GivingNamesPanel, find_name_issues
|
||||
from .notifications import notify_desktop
|
||||
from .syncthing import SyncthingPanel
|
||||
from .manual_resolution import ManualResolutionPanel
|
||||
from .refaire import SECTION as REFAIRE_SECTION
|
||||
from .refaire import (
|
||||
@@ -426,6 +427,7 @@ class CopienatorApp(tk.Tk):
|
||||
self.form.columnconfigure(1, weight=1)
|
||||
|
||||
command_box = ttk.LabelFrame(self.detail, text="Commande", padding=6)
|
||||
self.command_box = command_box
|
||||
command_box.grid(row=4, column=0, sticky="ew", pady=(8, 5))
|
||||
command_box.columnconfigure(0, weight=1)
|
||||
ttk.Label(command_box, textvariable=self.command_var, wraplength=690, justify="left").grid(
|
||||
@@ -782,6 +784,10 @@ class CopienatorApp(tk.Tk):
|
||||
if not step:
|
||||
return
|
||||
self._rendering = True
|
||||
if step.id == "personal_read":
|
||||
self.command_box.grid_remove()
|
||||
else:
|
||||
self.command_box.grid()
|
||||
redo = step.section == REFAIRE_SECTION
|
||||
expanded_form = redo or step.id in {
|
||||
"page_splitter",
|
||||
@@ -907,12 +913,32 @@ class CopienatorApp(tk.Tk):
|
||||
row += 1
|
||||
|
||||
self.run_button.configure(text="Enregistrer la sélection" if step.id == "refaire_selection" else ("Marquer terminée" if step.is_manual else "Exécuter"))
|
||||
if step.id == "personal_create":
|
||||
self.run_button.configure(text="Marquer Réussie")
|
||||
if step.id == "personal_read":
|
||||
self.run_button.configure(text="Marquer réussie")
|
||||
self.skip_button.configure(state="normal" if step.optional else "disabled")
|
||||
self._rendering = False
|
||||
self._update_command_preview()
|
||||
self._update_controls()
|
||||
|
||||
def _render_context_controls(self, step: StepDefinition, row: int) -> int:
|
||||
if step.id == "personal_read":
|
||||
controls = ttk.Frame(self.form)
|
||||
controls.grid(row=row, column=0, columnspan=2, sticky="w", pady=8)
|
||||
self.review_buttons = []
|
||||
for command in ("re", "wsn", "we"):
|
||||
button = ttk.Button(
|
||||
controls, text=f"gestion_classe {command}",
|
||||
command=lambda command=command: self._run_current_step(review_command=command),
|
||||
)
|
||||
button.pack(side="left", padx=(0, 6))
|
||||
self.review_buttons.append(button)
|
||||
return row + 1
|
||||
if step.id == "export":
|
||||
self.syncthing_panel = SyncthingPanel(self.form)
|
||||
self.syncthing_panel.grid(row=row, column=0, columnspan=2, sticky="ew", pady=8)
|
||||
return row + 1
|
||||
if step.id == "batch_status":
|
||||
controls = ttk.Frame(self.form)
|
||||
controls.grid(row=row, column=0, columnspan=2, sticky="w", pady=8)
|
||||
@@ -1407,9 +1433,13 @@ class CopienatorApp(tk.Tk):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _run_current_step(self) -> None:
|
||||
def _run_current_step(self, *, syncthing_ready=False, review_command=None) -> None:
|
||||
step = self.current_step
|
||||
evaluation = self.evaluation
|
||||
if review_command is not None and (
|
||||
not step or step.id != "personal_read" or review_command not in {"re", "wsn", "we"}
|
||||
):
|
||||
return
|
||||
if not step or not evaluation or not self.state_store.evaluation:
|
||||
messagebox.showerror("Évaluation absente", "Chargez d’abord un dossier d’évaluation.")
|
||||
return
|
||||
@@ -1427,7 +1457,8 @@ class CopienatorApp(tk.Tk):
|
||||
except (OSError, ValueError, TypeError) as exc:
|
||||
messagebox.showerror("Sélection à vérifier", str(exc))
|
||||
return
|
||||
if step.is_manual:
|
||||
if (step.is_manual or step.id == "personal_create"
|
||||
or (step.id == "personal_read" and review_command is None)):
|
||||
self._mark_step("success")
|
||||
self._move_selection_from(step.id, 1)
|
||||
return
|
||||
@@ -1456,6 +1487,8 @@ class CopienatorApp(tk.Tk):
|
||||
return
|
||||
variant = self._current_variant()
|
||||
command = self._make_command()
|
||||
if step.id == "personal_read":
|
||||
command = ["gestion_classe", review_command]
|
||||
if variant.dangerous and not messagebox.askyesno(
|
||||
"Nettoyage irréversible" if step.id == "clean" else "Confirmation requise",
|
||||
variant.danger_warning
|
||||
@@ -1464,6 +1497,13 @@ class CopienatorApp(tk.Tk):
|
||||
):
|
||||
return
|
||||
|
||||
if step.id == "export" and not syncthing_ready:
|
||||
def continue_export():
|
||||
if self.current_step is step and self.evaluation == evaluation:
|
||||
self._run_current_step(syncthing_ready=True)
|
||||
self.syncthing_panel.ensure_started(continue_export)
|
||||
return
|
||||
|
||||
self._save_current_form()
|
||||
run_values = self._values()
|
||||
ordered_ids = self._progression_ids(step.id)
|
||||
@@ -1701,7 +1741,7 @@ class CopienatorApp(tk.Tk):
|
||||
return
|
||||
stored_status = (
|
||||
"detected"
|
||||
if step_id == "giving_names" and status == "success"
|
||||
if step_id in {"giving_names", "personal_read"} and status == "success"
|
||||
else status
|
||||
)
|
||||
self.state_store.update_step(
|
||||
@@ -1732,6 +1772,10 @@ class CopienatorApp(tk.Tk):
|
||||
self.active_step_id = None
|
||||
self._populate_tree()
|
||||
self._update_controls()
|
||||
if step_id == "personal_read":
|
||||
if status == "success":
|
||||
self.info_var.set("Commande terminée. Poursuivez la relecture, puis cliquez sur « Marquer réussie ».")
|
||||
return
|
||||
if step_id == "giving_names" and status == "success":
|
||||
if self.giving_names_panel:
|
||||
self.giving_names_panel.reload()
|
||||
@@ -1820,6 +1864,9 @@ class CopienatorApp(tk.Tk):
|
||||
|
||||
def _update_controls(self) -> None:
|
||||
running = bool(self.active_step_id) or self.runner.running
|
||||
if self.current_step and self.current_step.id == "personal_read":
|
||||
for button in self.review_buttons:
|
||||
button.configure(state="disabled" if running or not self.state_store.evaluation else "normal")
|
||||
if self.current_step and self.current_step.id == "batch_status":
|
||||
self.watch_batches_button.configure(state="disabled" if running or self.batch_monitor.active or not self.state_store.evaluation else "normal")
|
||||
self.stop_watch_batches_button.configure(state="normal" if self.batch_monitor.active else "disabled")
|
||||
|
||||
@@ -633,7 +633,8 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
|
||||
"personal_create",
|
||||
"Étapes personnelles",
|
||||
"Créer l’interro dans gestion_classe",
|
||||
"Exécute gestion_classe ne.",
|
||||
"Copiez la commande gestion_classe ne et exécutez-la dans un terminal, "
|
||||
"puis cliquez sur « Marquer Réussie ».",
|
||||
(CommandVariant("default", "gestion_classe ne", "gestion_classe", "external", ("ne",)),),
|
||||
personal=True,
|
||||
),
|
||||
@@ -667,14 +668,14 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
|
||||
"personal_read",
|
||||
"Étapes personnelles",
|
||||
"Relire avec gestion_classe",
|
||||
"Exécute gestion_classe re.",
|
||||
"Utilisez les boutons gestion_classe re, wsn et we, puis cliquez sur « Marquer réussie ».",
|
||||
(CommandVariant("default", "gestion_classe re", "gestion_classe", "external", ("re",)),),
|
||||
personal=True,
|
||||
),
|
||||
StepDefinition(
|
||||
"personal_sent",
|
||||
"Étapes personnelles",
|
||||
"Marquer comme envoyé",
|
||||
"Écrire les notes finales",
|
||||
"Exécute gestion_classe wsent.",
|
||||
(CommandVariant("default", "gestion_classe wsent", "gestion_classe", "external", ("wsent",)),),
|
||||
personal=True,
|
||||
|
||||
@@ -27,6 +27,29 @@ class GuiConvenienceTests(unittest.TestCase):
|
||||
self.app.destroy()
|
||||
self.temp.cleanup()
|
||||
|
||||
def test_personal_review_commands_require_explicit_completion(self):
|
||||
from copienator_gui.workflow import build_workflow
|
||||
step = next(step for step in build_workflow(True) if step.id == "personal_read")
|
||||
self.app.step_by_id[step.id] = step
|
||||
self.app.current_step = step
|
||||
self.app._render_step()
|
||||
self.assertEqual([button.cget("text") for button in self.app.review_buttons],
|
||||
["gestion_classe re", "gestion_classe wsn", "gestion_classe we"])
|
||||
self.assertEqual(self.app.command_box.winfo_manager(), "")
|
||||
self.assertEqual(self.app.run_button.cget("text"), "Marquer réussie")
|
||||
with patch.object(self.app.runner, "start") as start, \
|
||||
patch.object(self.app, "_move_selection_from") as advance:
|
||||
for button, command in zip(self.app.review_buttons, ("re", "wsn", "we")):
|
||||
button.invoke()
|
||||
self.assertEqual(start.call_args.args[0], ["gestion_classe", command])
|
||||
self.app._finish_process(0, False)
|
||||
self.assertNotEqual(self.app.state_store.step(step.id)["status"], "success")
|
||||
advance.assert_not_called()
|
||||
start.reset_mock()
|
||||
self.app.run_button.invoke()
|
||||
start.assert_not_called()
|
||||
self.assertEqual(self.app.state_store.step(step.id)["status"], "success")
|
||||
|
||||
@staticmethod
|
||||
def _label_texts(widget):
|
||||
return [
|
||||
|
||||
Reference in new issue
Block a user