diff --git a/app/api/formations.py b/app/api/formations.py
index 37bf6ccf6f2a594eca40cc5d283c8b1256240d7f..53d821a0595e36699102723f9b1b268248c2e83a 100644
--- a/app/api/formations.py
+++ b/app/api/formations.py
@@ -329,6 +329,8 @@ def desassoc_ue_niveau(ue_id: int):
     ue.niveau_competence = None
     db.session.add(ue)
     db.session.commit()
+    # Invalidation du cache
+    ue.formation.invalidate_cached_sems()
     log(f"desassoc_ue_niveau: {ue}")
     if g.scodoc_dept:
         # "usage web"
diff --git a/app/but/apc_edit_ue.py b/app/but/apc_edit_ue.py
index 0ae48a2181c5b9bf983c9fc5fe91cf62d3a5c49f..0a7a1201ac93f63d541c3901810e2ff06667c78e 100644
--- a/app/but/apc_edit_ue.py
+++ b/app/but/apc_edit_ue.py
@@ -21,7 +21,7 @@ def form_ue_choix_parcours(ue: UniteEns) -> str:
         return ""
     ref_comp = ue.formation.referentiel_competence
     if ref_comp is None:
-        return f"""<div class="ue_advanced">
+        return f"""<div class="scobox ue_advanced">
         <div class="warning">Pas de référentiel de compétence associé à cette formation !</div>
         <div><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation',
                          scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)
@@ -31,8 +31,8 @@ def form_ue_choix_parcours(ue: UniteEns) -> str:
 
     H = [
         """
-    <div class="ue_advanced">
-    <h3>Parcours du BUT</h3>
+    <div class="scobox ue_advanced">
+    <div class="scobox-title">Parcours du BUT</div>
     """
     ]
     # Choix des parcours
@@ -43,7 +43,6 @@ def form_ue_choix_parcours(ue: UniteEns) -> str:
         ue.get_ects(parcour, only_parcours=True) for parcour in ref_comp.parcours
     } != {None}
     for parcour in ref_comp.parcours:
-        ects_parcour = ue.get_ects(parcour)
         ects_parcour_txt = (
             f" ({ue.get_ects(parcour):.3g} ects)" if ects_differents else ""
         )
diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py
index 061227114035a7aa197a9c9225e25e3ecdae3b1e..faf3199b0ed5ee0cb447066b0bcb66db3ce00cd5 100644
--- a/app/scodoc/sco_edit_ue.py
+++ b/app/scodoc/sco_edit_ue.py
@@ -298,27 +298,6 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
     cursus = formation.get_cursus()
     is_apc = cursus.APC_SAE
     semestres_indices = list(range(1, cursus.NB_SEM + 1))
-    H = [
-        html_sco_header.sco_header(page_title=title, javascripts=["js/edit_ue.js"]),
-        "<h2>" + title,
-        f" (formation {formation.acronyme}, version {formation.version})</h2>",
-        """
-    <p class="help">Les UE sont des groupes de modules dans une formation donnée,
-    utilisés pour la validation (on calcule des moyennes par UE et applique des
-    seuils ("barres")).
-    </p>
-
-    <p class="help">Note: sauf exception, l'UE n'a pas de coefficient associé.
-    Seuls les <em>modules</em> ont des coefficients.
-    </p>""",
-        (
-            f"""
-    <h4>UE du semestre S{ue.semestre_idx}</h4>
-    """
-            if is_apc and ue
-            else ""
-        ),
-    ]
 
     ue_types = cursus.ALLOWED_UE_TYPES
     ue_types.sort()
@@ -489,7 +468,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
         if ue and is_apc:
             ue_parcours_div = apc_edit_ue.form_ue_choix_parcours(ue)
         if ue and ue.modules.count() and ue.semestre_idx is not None:
-            modules_div = f"""<div id="ue_list_modules">
+            modules_div = f"""<div class="scobox" id="ue_list_modules">
             <div><b>{ue.modules.count()} modules sont rattachés
             à cette UE</b> du semestre S{ue.semestre_idx},
             elle ne peut donc pas être changée de semestre.</div>
@@ -511,18 +490,34 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
             """
         else:
             clone_form = ""
-        bonus_div = """<div id="bonus_description"></div>"""
-        ue_div = """<div id="ue_list_code" class="sco_box sco_green_bg"></div>"""
-        return (
-            "\n".join(H)
-            + tf[1]
-            + clone_form
-            + ue_parcours_div
-            + modules_div
-            + bonus_div
-            + ue_div
-            + html_sco_header.sco_footer()
-        )
+
+        return f"""
+        {html_sco_header.sco_header(page_title=title, javascripts=["js/edit_ue.js"])}
+        <h2>{title}, (formation {formation.acronyme}, version {formation.version})</h2>
+        <p class="help">Les UEs sont des groupes de modules dans une formation donnée,
+        utilisés pour la validation (on calcule des moyennes par UE et applique des
+        seuils ("barres")).
+        </p>
+
+        <p class="help">Note: sauf exception, l'UE n'a pas de coefficient associé.
+        Seuls les <em>modules</em> ont des coefficients.
+        </p>
+
+        <div class="scobox">
+            <div class="scobox-title">
+            Édition de l'UE {('du semestre S'+str(ue.semestre_idx)) if is_apc and ue else ''}
+            </div>
+            {tf[1]}
+        </div>
+        {clone_form}
+        {ue_parcours_div}
+        {modules_div}
+
+        <div id="bonus_description"></div>
+        <div id="ue_list_code" class="sco_box sco_green_bg"></div>
+
+        {html_sco_header.sco_footer()}
+        """
     elif tf[0] == 1:
         if create:
             if not tf[2]["ue_code"]:
@@ -1170,14 +1165,17 @@ def _ue_table_ues(
                 if has_perm_change:
                     H.append(
                         f"""<a class="stdlink" href="{
-                            url_for("notes.ue_set_internal", scodoc_dept=g.scodoc_dept, ue_id=ue["ue_id"])
+                            url_for("notes.ue_set_internal",
+                                scodoc_dept=g.scodoc_dept, ue_id=ue["ue_id"])
                             }">transformer en UE ordinaire</a>&nbsp;"""
                     )
                 H.append("</span>")
         ue_editable = editable and not ue_is_locked(ue["ue_id"])
         if ue_editable:
             H.append(
-                '<a class="stdlink" href="ue_edit?ue_id=%(ue_id)s">modifier</a>' % ue
+                f"""<a class="stdlink" href="{
+                        url_for("notes.ue_edit", scodoc_dept=g.scodoc_dept, ue_id=ue["ue_id"])
+                    }">modifier</a>"""
             )
         else:
             H.append('<span class="locked">[verrouillé]</span>')
diff --git a/app/views/notes.py b/app/views/notes.py
index ea190b4f17cf4c2b095fbaca80472bb1af94bd83..1bdccf8641095c54afcc945d5f1455dbe1447e13 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -45,7 +45,6 @@ from app import models
 from app.auth.models import User
 from app.but import (
     apc_edit_ue,
-    bulletin_but_court,  # ne pas enlever: ajoute des routes !
     cursus_but,
     jury_edit_manual,
     jury_but,
@@ -53,6 +52,8 @@ from app.but import (
     jury_but_validation_auto,
     jury_but_view,
 )
+from app.but import bulletin_but_court  # ne pas enlever: ajoute des routes !
+
 from app.but.forms import jury_but_forms
 
 
@@ -449,12 +450,14 @@ sco_publish(
     Permission.EditFormation,
     methods=["GET", "POST"],
 )
-sco_publish(
-    "/ue_edit",
-    sco_edit_ue.ue_edit,
-    Permission.EditFormation,
-    methods=["GET", "POST"],
-)
+
+
+@bp.route("/ue_edit/<int:ue_id>", methods=["GET", "POST"])
+@scodoc
+@permission_required(Permission.EditFormation)
+def ue_edit(ue_id: int):
+    "Edition de l'UE"
+    return sco_edit_ue.ue_edit(ue_id)
 
 
 @bp.route("/set_ue_niveau_competence", methods=["POST"])
@@ -504,7 +507,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""):
 @bp.route("/ue_infos/<int:ue_id>")
 @scodoc
 @permission_required(Permission.ScoView)
-def ue_infos(ue_id):
+def ue_infos(ue_id: int):
     ue = UniteEns.query.get_or_404(ue_id)
     return sco_edit_apc.html_ue_infos(ue)