feat(web): éditeur de périodes modifiables dans les réglages

La page Réglages permet maintenant de créer, modifier et supprimer ses propres périodes (profils) : nom, travail, pause courte, pause longue et nombre de cycles, avec bouton radio ★ pour choisir la période active. Enregistrement via profiles_json + active_profile (index). Repli automatique sur la première période si l'active est supprimée ; noms vides/doublons ignorés. La page Aide affiche le tableau des périodes réelles de la configuration. Tests : parsing, édition, repli du profil actif et intégration HTTP.
This commit is contained in:
2026-08-14 23:37:23 -04:00
parent 162d574ff4
commit b47bf61386
3 changed files with 189 additions and 38 deletions
+44 -6
View File
@@ -43,8 +43,11 @@ suite "applySettings":
test "applies a full form":
let base = defaultConfig()
let form = parseForm("workMin=40&shortBreakMin=8&longBreakMin=20&" &
"cyclesBeforeLongBreak=5&dailyGoal=6&lang=en&activeProfile=Sprint&" &
"soundEnabled=on&doNotDisturb=on&" &
"cyclesBeforeLongBreak=5&dailyGoal=6&lang=en&" &
"active_profile=1&" &
"profiles_json=" & encodeUrl(
"""[{"name":"Focus","workMin":30,"shortBreakMin":6,"longBreakMin":18,"cycles":4},{"name":"Rapide","workMin":10,"shortBreakMin":2,"longBreakMin":5,"cycles":3}]""") &
"&soundEnabled=on&doNotDisturb=on&" &
"reminders_json=" & encodeUrl("""[{"text":"Boire de l'eau","enabled":true}]"""))
let cfg = applySettings(base, form)
check cfg.workMin == 40
@@ -53,16 +56,43 @@ suite "applySettings":
check cfg.cyclesBeforeLongBreak == 5
check cfg.dailyGoal == 6
check cfg.lang == "en"
check cfg.activeProfile == "Sprint"
check cfg.profiles.len == 2
check cfg.profiles[0].name == "Focus"
check cfg.profiles[1].workMin == 10
check cfg.activeProfile == "Rapide"
check cfg.soundEnabled
check cfg.doNotDisturb
check not cfg.autoStart
check cfg.healthReminders.len == 1
check cfg.healthReminders[0].text == "Boire de l'eau"
test "profiles are edited and active profile falls back safely":
let base = defaultConfig()
# Deux périodes, active = index 1.
let f1 = parseForm("profiles_json=" & encodeUrl(
"""[{"name":"A","workMin":25,"shortBreakMin":5,"longBreakMin":15,"cycles":4},{"name":"B","workMin":50,"shortBreakMin":10,"longBreakMin":20,"cycles":5}]""") &
"&active_profile=1")
let c1 = applySettings(base, f1)
check c1.profiles.len == 2
check c1.activeProfile == "B"
# Index hors limites (période active supprimée) : repli sur la première.
let f2 = parseForm("profiles_json=" & encodeUrl(
"""[{"name":"C","workMin":20,"shortBreakMin":4,"longBreakMin":10,"cycles":3}]""") &
"&active_profile=5")
let c2 = applySettings(base, f2)
check c2.profiles.len == 1
check c2.activeProfile == "C"
# Noms vides et doublons ignorés.
let f3 = parseForm("profiles_json=" & encodeUrl(
"""[{"name":"","workMin":1,"shortBreakMin":1,"longBreakMin":1,"cycles":1},{"name":"D","workMin":33,"shortBreakMin":3,"longBreakMin":9,"cycles":2},{"name":"D","workMin":99,"shortBreakMin":9,"longBreakMin":27,"cycles":9}]"""))
let c3 = applySettings(base, f3)
check c3.profiles.len == 1
check c3.profiles[0].name == "D"
check c3.profiles[0].workMin == 33
test "invalid values fall back to current ones":
let base = defaultConfig()
let form = parseForm("workMin=abc&lang=zz&activeProfile=Inexistant")
let form = parseForm("workMin=abc&lang=zz&active_profile=99")
let cfg = applySettings(base, form)
check cfg.workMin == base.workMin
check cfg.lang == "auto"
@@ -78,6 +108,8 @@ suite "rendering":
check "Réglages" in renderSettings(cfg)
check "name='workMin'" in renderSettings(cfg)
check "reminders_json" in renderSettings(cfg)
check "profiles_json" in renderSettings(cfg)
check "active_profile" in renderSettings(cfg)
suite "integration (local HTTP server)":
test "GET routes work and settings POST persists":
@@ -109,8 +141,10 @@ suite "integration (local HTTP server)":
# Sauvegarde via POST (comme le ferait le navigateur).
let body = "workMin=33&shortBreakMin=6&longBreakMin=18&cyclesBeforeLongBreak=4&" &
"dailyGoal=5&lang=fr&activeProfile=Classique&" &
"reminders_json=" & encodeUrl(
"dailyGoal=5&lang=fr&active_profile=1&" &
"profiles_json=" & encodeUrl(
"""[{"name":"Zen","workMin":35,"shortBreakMin":7,"longBreakMin":20,"cycles":4},{"name":"Bolt","workMin":5,"shortBreakMin":1,"longBreakMin":3,"cycles":2}]""") &
"&reminders_json=" & encodeUrl(
"""[{"text":"Étire-toi","enabled":true},{"text":"Bois de l'eau","enabled":false}]""")
let resp = client.postContent(base & "/settings", body)
check "Réglages enregistrés" in resp
@@ -120,6 +154,10 @@ suite "integration (local HTTP server)":
check saved.workMin == 33
check saved.dailyGoal == 5
check saved.lang == "fr"
check saved.profiles.len == 2
check saved.profiles[0].name == "Zen"
check saved.profiles[1].workMin == 5
check saved.activeProfile == "Bolt"
check saved.healthReminders.len == 2
check saved.healthReminders[1].enabled == false