Page accueil département: refonte liste semestres en cours

This commit is contained in:
Emmanuel Viennet 2024-03-26 14:17:42 +01:00
parent 09ec53f573
commit bae46c2794
5 changed files with 139 additions and 76 deletions

View File

@ -208,7 +208,7 @@ class FormSemestre(models.ScoDocModel):
return cls.query.filter_by(id=formsemestre_id).first_or_404() return cls.query.filter_by(id=formsemestre_id).first_or_404()
def sort_key(self) -> tuple: def sort_key(self) -> tuple:
"""clé pour tris par ordre alphabétique """clé pour tris par ordre de date_debut, le plus ancien en tête
(pour avoir le plus récent d'abord, sort avec reverse=True)""" (pour avoir le plus récent d'abord, sort avec reverse=True)"""
return (self.date_debut, self.semestre_id) return (self.date_debut, self.semestre_id)

View File

@ -79,21 +79,30 @@ def index_html(showcodes=0, showsemtable=0, export_table_formsemestres=False):
else: else:
html_table_formsemestres = None html_table_formsemestres = None
current_formsemestres_by_modalite, modalites = (
sco_modalites.group_formsemestres_by_modalite(current_formsemestres)
)
return render_template( return render_template(
"scolar/index.j2", "scolar/index.j2",
current_user=current_user, current_user=current_user,
current_formsemestres=current_formsemestres,
current_formsemestres_by_modalite=current_formsemestres_by_modalite,
dept_name=sco_preferences.get_preference("DeptName"), dept_name=sco_preferences.get_preference("DeptName"),
formsemestres=formsemestres, emptygroupicon=scu.icontag(
html_current_formsemestres=_show_current_formsemestres( "emptygroupicon_img", title="Pas d'inscrits", border="0"
current_formsemestres, showcodes
), ),
formsemestres=formsemestres,
groupicon=scu.icontag("groupicon_img", title="Inscrits", border="0"),
html_table_formsemestres=html_table_formsemestres, html_table_formsemestres=html_table_formsemestres,
locked_formsemestres=locked_formsemestres, locked_formsemestres=locked_formsemestres,
modalites=modalites,
nb_locked=locked_formsemestres.count(), nb_locked=locked_formsemestres.count(),
nb_user_accounts=sco_users.get_users_count(dept=g.scodoc_dept), nb_user_accounts=sco_users.get_users_count(dept=g.scodoc_dept),
page_title=f"ScoDoc {g.scodoc_dept}", page_title=f"ScoDoc {g.scodoc_dept}",
Permission=Permission, Permission=Permission,
scolar_news_summary=ScolarNews.scolar_news_summary_html(), scolar_news_summary=ScolarNews.scolar_news_summary_html(),
showcodes=showcodes,
showsemtable=showsemtable, showsemtable=showsemtable,
sco=ScoData(), sco=ScoData(),
) )
@ -116,6 +125,7 @@ def _convert_formsemestres_to_dicts(
lockicon = "X" lockicon = "X"
# génère liste de dict # génère liste de dict
sems = [] sems = []
formsemestre: FormSemestre
for formsemestre in formsemestres: for formsemestre in formsemestres:
nb_inscrits = len(formsemestre.inscriptions) nb_inscrits = len(formsemestre.inscriptions)
formation = formsemestre.formation formation = formsemestre.formation
@ -151,61 +161,6 @@ def _convert_formsemestres_to_dicts(
return sems return sems
def _show_current_formsemestres(formsemestres: Query, showcodes: bool) -> str:
"""html div avec les formsemestres courants de la page d'accueil"""
H = []
if formsemestres.count():
H.append("""<div class="scobox-title">Sessions en cours</div>""")
H.append(_sem_table(_convert_formsemestres_to_dicts(formsemestres, showcodes)))
else:
# aucun semestre courant: affiche aide
H.append(
"""
<div class="scobox-title">Aucune session en cours !</div>
<p>Pour ajouter une session, aller dans <a href="Notes" id="link-programmes">Formations</a>,
choisissez une formation, puis suivez le lien "<em>UE, modules, semestres</em>".
</p>
<p>, en bas de page, suivez le lien
"<em>Mettre en place un nouveau semestre de formation...</em>"
</p>"""
)
return "\n".join(H)
def _sem_table(sems: list[dict]) -> str:
"""Affiche liste des semestres, utilisée pour semestres en cours"""
tmpl = f"""<tr class="%(trclass)s">%(tmpcode)s
<td class="semicon">%(lockimg)s <a href="{
url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept)}?formsemestre_id=%(formsemestre_id)s#groupes">%(groupicon)s</a></td>
<td class="datesem">%(mois_debut)s <a title="%(session_id)s">-</a> %(mois_fin)s</td>
<td class="titresem"><a class="stdlink" href="{url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept)}?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a>
<span class="respsem">(%(responsable_name)s)</span>
</td>
</tr>
"""
# Liste des semestres, groupés par modalités
sems_by_mod, modalites = sco_modalites.group_sems_by_modalite(sems)
H = ['<table class="listesems">']
for modalite in modalites:
if len(modalites) > 1:
H.append('<tr><th colspan="3">%s</th></tr>' % modalite["titre"])
if sems_by_mod[modalite["modalite"]]:
cur_idx = sems_by_mod[modalite["modalite"]][0]["semestre_id"]
for sem in sems_by_mod[modalite["modalite"]]:
if cur_idx != sem["semestre_id"]:
sem["trclass"] = "firstsem" # separe les groupes de semestres
cur_idx = sem["semestre_id"]
else:
sem["trclass"] = ""
H.append(tmpl % sem)
H.append("</table>")
return "\n".join(H)
def _sem_table_gt(formsemestres: Query, showcodes=False, fmt="html") -> GenTable: def _sem_table_gt(formsemestres: Query, showcodes=False, fmt="html") -> GenTable:
"""Table des semestres """Table des semestres
Utilise une datatables. Utilise une datatables.

View File

@ -36,37 +36,45 @@ Elle n'est pas utilisée pour les parcours, ni pour rien d'autre
import collections import collections
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app import log from app import log
from app.models import FormSemestre
def list_formsemestres_modalites(sems): def list_formsemestres_modalites(formsemestres: list[FormSemestre]) -> list[dict]:
"""Liste ordonnée des modalités présentes dans ces formsemestres""" """Liste ordonnée des modalités présentes dans ces formsemestres"""
modalites = {} modalites = {}
for sem in sems: for formsemestre in formsemestres:
if sem["modalite"] not in modalites: if formsemestre.modalite not in modalites:
m = do_modalite_list(args={"modalite": sem["modalite"]})[0] m = do_modalite_list(args={"modalite": formsemestre.modalite})[0]
modalites[m["modalite"]] = m modalites[m["modalite"]] = m
modalites = list(modalites.values()) modalites = list(modalites.values())
modalites.sort(key=lambda x: x["numero"]) modalites.sort(key=lambda x: x["numero"])
return modalites return modalites
def group_sems_by_modalite(sems: list[dict]): def group_formsemestres_by_modalite(
formsemestres: list[FormSemestre],
) -> dict[str, list[FormSemestre]]:
"""Given the list of formsemestre, group them by modalite, """Given the list of formsemestre, group them by modalite,
sorted in each one by semestre id and date sorted in each one by semestre id and date
""" """
sems_by_mod = collections.defaultdict(list) sems_by_mod = collections.defaultdict(list)
modalites = list_formsemestres_modalites(sems) modalites = list_formsemestres_modalites(formsemestres)
for modalite in modalites: sems_by_mod = {
for sem in sems: modalite["modalite"]: [
if sem["semestre_id"] < 0: # formations en un semestre formsemestre
sem["sortkey"] = (-100 * sem["semestre_id"], sem["dateord"]) for formsemestre in formsemestres
else: if formsemestre.modalite == modalite["modalite"]
sem["sortkey"] = (sem["semestre_id"], sem["dateord"]) ]
if sem["modalite"] == modalite["modalite"]: for modalite in modalites
sems_by_mod[modalite["modalite"]].append(sem) }
# tri dans chaque modalité par indice de semestre et date debut # tri dans chaque modalité par indice de semestre et date debut
for modalite in modalites: for modalite in modalites:
sems_by_mod[modalite["modalite"]].sort(key=lambda x: x["sortkey"]) sems_by_mod[modalite["modalite"]].sort(
key=lambda x: (
x.semestre_id if x.semestre_id > 0 else -1000 * x.semestre_id,
x.date_debut,
)
)
return sems_by_mod, modalites return sems_by_mod, modalites

View File

@ -83,6 +83,70 @@ table.semlist tbody tr td.modalite {
padding-right: 1em; padding-right: 1em;
} }
div.modalite {
font-size: 16px;
font-weight: bold;
}
span.effectif {
display: inline-block;
min-width: 24px;
text-align: right;
}
.cur-formsemestres {
width: max-content; /* Fits content, but respects max-width */
max-width: 1024px; /* Maximum width */
margin: 0 auto 0 0; /* Centers divs if they are narrower than 1024px */
}
.cur-formsemestre {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #ddd;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;;
background-color: rgb(246, 255, 254);
padding: 0px 8px 0px 8px;
margin: 0px;
}
.cur-formsemestre.new-sem {
margin-top: 8px;
border-top: 1px solid #ddd;;
}
.left-section {
display: flex;
align-items: center;
}
.date {
display: flex;
flex-direction: column;
margin-left: 10px;
font-size: 12px;
}
.cur-formsemestre .title {
flex-grow: 1;
text-align: left;
margin: 0 20px;
display: flex;
align-items: center;
font-size: 16px;
}
.right-section {
display: flex;
flex-direction: column;
font-size: 14px;
}
.responsable {
font-weight: bold;
color: navy;
}
</style> </style>
{# News #} {# News #}
@ -103,7 +167,43 @@ table.semlist tbody tr td.modalite {
{# Les semestres courants (cad non verrouillés) #} {# Les semestres courants (cad non verrouillés) #}
<div class="scobox"> <div class="scobox">
{{html_current_formsemestres|safe}} {% if current_formsemestres.count() == 0 %}
<div class="scobox-title">Aucune session en cours !</div>
<p>Pour ajouter une session, aller dans <a href="Notes" id="link-programmes">Formations</a>,
choisissez une formation, puis suivez le lien "<em>UE, modules, semestres</em>".
</p>
<p>Là, en bas de page, suivez le lien
"<em>Mettre en place un nouveau semestre de formation...</em>"
</p>
{% else %}
<div class="scobox-title">Sessions en cours</div>
<div class="cur-formsemestres">
{% for modalite in modalites %}
{% if modalites|length > 1 %}
<div class="modalite">{{modalite.titre}}</div>
{% endif %}
{% for formsemestre in current_formsemestres_by_modalite[modalite.modalite] %}
<div class="cur-formsemestre {{'new-sem' if loop.first or formsemestre.semestre_id != loop.previtem.semestre_id}}">
<div class="left-section">
{{groupicon|safe if formsemestre.inscriptions|length else emptygroupicon|safe}}
<div class="date">
<div class="date-begin"><a title="{{formsemestre.session_id()}}">{{formsemestre.mois_debut()}}</a></div>
<div class="date-end">{{formsemestre.mois_fin()}}</div>
</div>
</div>
<div class="title">
<a class="stdlink" href="{{ url_for("notes.formsemestre_status",
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id)}}">{{formsemestre.titre_num()}}</a>
</div>
<div class="right-section">
<div class="responsable">{{formsemestre.responsables_str()}}</div>
<div class="effectif">{{formsemestre.inscriptions|length}} étuds</div>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
{% endif %}
</div> </div>
{# Table de tous les semestres #} {# Table de tous les semestres #}

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.6.954" SCOVERSION = "9.6.955"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"