diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py
index 4c1a63401..602289db4 100644
--- a/app/scodoc/sco_recapcomplet.py
+++ b/app/scodoc/sco_recapcomplet.py
@@ -108,7 +108,8 @@ def formsemestre_recapcomplet(
return data
H = [
html_sco_header.sco_header(
- page_title=f"{formsemestre.sem_modalite()}: moyennes",
+ page_title=f"{formsemestre.sem_modalite()}: "
+ + ("jury" if mode_jury else "moyennes"),
no_side_bar=True,
init_qtip=True,
javascripts=["js/etud_info.js", "js/table_recap.js"],
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 0898786a7..84b3e1708 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -3992,6 +3992,29 @@ div.table_recap {
margin-top: 6px;
}
+.table_recap .but_on {
+ background-color: rgb(177, 238, 162);
+ font-weight: bold;
+}
+
+.table_recap .but_off {
+ background-color: lightgray;
+}
+
+.table_recap button.but_on:hover:not(.disabled),
+.table_recap div.but_on:hover:not(.disabled),
+.table_recap a.but_on:hover:not(.disabled),
+.table_recap input.but_on:hover:not(.disabled) {
+ background: linear-gradient(to bottom, lightgray 0%, rgb(51, 255, 0) 100%);
+}
+
+.table_recap button.but_off:hover:not(.disabled),
+.table_recap div.but_off:hover:not(.disabled),
+.table_recap a.but_off:hover:not(.disabled),
+.table_recap input.but_off:hover:not(.disabled) {
+ background: linear-gradient(to bottom, rgb(51, 255, 0) 0%, lightgray 100%);
+}
+
div.table_recap table.table_recap {
width: auto;
/* font-family: Consolas, monaco, monospace; */
diff --git a/app/static/js/table_recap.js b/app/static/js/table_recap.js
index 2c4882a9b..bc3c1ef4c 100644
--- a/app/static/js/table_recap.js
+++ b/app/static/js/table_recap.js
@@ -32,146 +32,141 @@ $(function () {
}
}
- // Les colonnes visibles étant mémorisées, il faut initialiser les titres des boutons
+ // Les colonnes visibles sont mémorisées, il faut initialiser l'état des boutons
function update_buttons_labels(dt) {
- console.log("update_buttons_labels");
- dt.buttons('toggle_ident:name').text(dt.columns(".identite_detail").visible()[0] ? "Nom seul" : "Civ/Nom/Prénom");
- dt.buttons('toggle_partitions:name').text(dt.columns(".partition_aux").visible()[0] ? "Cacher les groupes" : "Montrer groupes");
- if (!$('table.table_recap').hasClass("table_jury_but")) {
- // Bouton "rangs groupes", sauf pour table jury BUT
- dt.buttons('toggle_partitions_rangs:name').text(dt.columns(".partition_rangs").visible()[0] ? "Cacher rangs groupes" : "Rangs groupes");
- dt.buttons('toggle_admission:name').text(dt.columns(".admission").visible()[0] ? "Cacher infos admission" : "Montrer infos admission");
- } else {
- // table jury BUT: avec ou sans codes enregistrés
- dt.buttons('toggle_recorded_code:name').text(dt.columns(".recorded_code").visible()[0] ? "Cacher codes jury" : "Code jury enregistrés");
- }
-
- // Boutons non visibles en mode jury:
- if (!$('table.table_recap').hasClass("jury")) {
- // Ces boutons dépendent du mode BUT ou classique:
- if ($('table.table_recap').hasClass("apc")) {
- dt.buttons('toggle_res:name').text(dt.columns(".col_res").visible()[0] ? "Cacher les ressources" : "Montrer les ressources");
- dt.buttons('toggle_sae:name').text(dt.columns(".col_sae").visible()[0] ? "Cacher les SAÉs" : "Montrer les SAÉs");
- } else {
- dt.buttons('toggle_mod:name').text(dt.columns(".col_mod:not(.col_empty)").visible()[0] ? "Cacher les modules" : "Montrer les modules");
+ // chaque bouton controle une classe stockée dans le data-group du span
+ document.querySelectorAll("button.dt-button").forEach(but => {
+ let g_span = but.querySelector("span > span");
+ if (g_span) {
+ let group = g_span.dataset["group"];
+ if (group) {
+ // si le group (= la 1ere col.) est visible, but_on
+ if (dt.columns("." + group).visible()[0]) {
+ but.classList.add("but_on");
+ but.classList.remove("but_off");
+ } else {
+ but.classList.add("but_off");
+ but.classList.remove("but_on");
+ }
+ }
}
- dt.buttons('toggle_col_empty:name').text(dt.columns(".col_empty").visible()[0] ? "Cacher mod. vides" : "Montrer mod. vides");
- }
+ });
}
+ // Changement visibilité groupes colonnes (boutons)
+ function toggle_col_but_visibility(e, dt, node, config) {
+ let group = node.children()[0].firstChild.dataset.group;
+ toggle_col_group_visibility(dt, group, node.hasClass("but_on"));
+ }
+ function toggle_col_ident_visibility(e, dt, node, config) {
+ let onoff = node.hasClass("but_on");
+ toggle_col_group_visibility(dt, "identite_detail", onoff);
+ toggle_col_group_visibility(dt, "identite_court", !onoff);
+ }
+ function toggle_col_ressources_visibility(e, dt, node, config) {
+ let onoff = node.hasClass("but_on");
+ toggle_col_group_visibility(dt, "col_res", onoff);
+ toggle_col_group_visibility(dt, "col_ue_bonus", onoff);
+ toggle_col_group_visibility(dt, "col_malus", onoff);
+ }
+ function toggle_col_group_visibility(dt, group, onoff) {
+ if (onoff) {
+ dt.columns('.' + group).visible(false);
+ } else {
+ dt.columns('.' + group).visible(true);
+ }
+ update_buttons_labels(dt);
+ }
+ // Definition des boutons au dessus de la table:
let buttons = [
{
- name: "toggle_ident",
- text: "Civ/Nom/Prénom",
+ extend: 'copyHtml5',
+ text: 'Copier',
+ exportOptions: { orthogonal: 'export' }
+ },
+ {
+ extend: 'excelHtml5',
+ // footer: true, // ne fonctionne pas ?
+ exportOptions: { orthogonal: 'export' },
+ title: document.querySelector('table.table_recap').dataset.filename
+ },
+ {
+ // force affichage de toutes les colonnes
+ text: '✴',
action: function (e, dt, node, config) {
- let visible = dt.columns(".identite_detail").visible()[0];
- dt.columns(".identite_detail").visible(!visible);
- dt.columns(".identite_court").visible(visible);
+ dt.columns().visible(true);
update_buttons_labels(dt);
}
},
{
- name: "toggle_partitions",
- text: "Montrer groupes",
+ text: '➗',
action: function (e, dt, node, config) {
- let visible = dt.columns(".partition_aux").visible()[0];
- dt.columns(".partition_aux").visible(!visible);
- update_buttons_labels(dt);
+ localStorage.clear();
+ console.log("cleared localStorage");
+ location.reload();
}
},
- ];
- // Bouton "rangs groupes", sauf pour table jury BUT
- if (!$('table.table_recap').hasClass("table_jury_but")) {
+ {
+ text: 'Civilité',
+ action: toggle_col_ident_visibility,
+ },
+ {
+ text: 'Groupes',
+ action: toggle_col_but_visibility,
+ },
+ {
+ text: 'Rg',
+ action: toggle_col_but_visibility,
+ },
+ ]; // fin des boutons communs à toutes les tables recap
+
+ if ($('table.table_recap').hasClass("jury")) {
+ // table jury: avec ou sans codes enregistrés
buttons.push(
{
- name: "toggle_partitions_rangs",
- text: "Rangs groupes",
- action: function (e, dt, node, config) {
- let rangs_visible = dt.columns(".partition_rangs").visible()[0];
- dt.columns(".partition_rangs").visible(!rangs_visible);
- update_buttons_labels(dt);
- }
+ text: 'Code jurys',
+ action: toggle_col_but_visibility,
});
} else {
- // table jury BUT: avec ou sans codes enregistrés
- buttons.push(
- {
- name: "toggle_recorded_code",
- text: "Code jury enregistrés",
- action: function (e, dt, node, config) {
- let visible = dt.columns(".recorded_code").visible()[0];
- dt.columns(".recorded_code").visible(!visible);
- update_buttons_labels(dt);
- }
- });
- }
-
- if (!$('table.table_recap').hasClass("jury")) {
+ // BOUTONS SPECIFIQUES A LA TABLE RECAP NON JURY
buttons.push(
$('table.table_recap').hasClass("apc") ?
{
- name: "toggle_res",
- text: "Visibilité ressources",
- action: function (e, dt, node, config) {
- let visible = dt.columns(".col_res").visible()[0];
- dt.columns(".col_res").visible(!visible);
- dt.columns(".col_ue_bonus").visible(!visible);
- dt.columns(".col_malus").visible(!visible);
- update_buttons_labels(dt);
- }
+ text: 'Ressources',
+ action: toggle_col_ressources_visibility,
} : {
name: "toggle_mod",
text: "Cacher les modules",
action: function (e, dt, node, config) {
- let visible = dt.columns(".col_mod:not(.col_empty)").visible()[0];
- dt.columns(".col_mod:not(.col_empty)").visible(!visible);
- dt.columns(".col_ue_bonus").visible(!visible);
- dt.columns(".col_malus").visible(!visible);
- update_buttons_labels(dt);
+ let onoff = node.hasClass("but_on");
+ toggle_col_group_visibility(dt, "col_mod:not(.col_empty)", onoff);
+ toggle_col_group_visibility(dt, "col_ue_bonus", onoff);
+ toggle_col_group_visibility(dt, "col_malus", onoff);
}
}
);
if ($('table.table_recap').hasClass("apc")) {
buttons.push({
- name: "toggle_sae",
- text: "Visibilité SAÉs",
- action: function (e, dt, node, config) {
- let visible = dt.columns(".col_sae").visible()[0];
- dt.columns(".col_sae").visible(!visible);
- update_buttons_labels(dt);
- }
- })
+ text: 'SAÉs',
+ action: toggle_col_but_visibility,
+ });
}
- buttons.push({
- name: "toggle_col_empty",
- text: "Visibilité mod. vides",
- action: function (e, dt, node, config) {
- let visible = dt.columns(".col_empty").visible()[0];
- dt.columns(".col_empty").visible(!visible);
- update_buttons_labels(dt);
- }
- })
- }
- // Boutons admission, sauf pour table jury BUT
- if (!$('table.table_recap').hasClass("table_jury_but")) {
- buttons.push({
- name: "toggle_admission",
- text: "Montrer infos admission",
- action: function (e, dt, node, config) {
- let visible = dt.columns(".admission").visible()[0];
- dt.columns(".admission").visible(!visible);
- update_buttons_labels(dt);
- }
+ buttons.push({ // modules vides
+ text: 'Vides',
+ action: toggle_col_but_visibility,
});
- }
- buttons.push({
- name: "reset_table_display",
- text: "Rétablir affichage par défaut",
- action: function (e, dt, node, config) {
- localStorage.clear();
- location.reload();
+ // Boutons admission (pas en jury)
+ if (!$('table.table_recap').hasClass("jury")) {
+ buttons.push(
+ {
+ text: 'Admission',
+ action: toggle_col_but_visibility,
+ }
+ );
}
- });
+ }
+
+ // ------------- LA TABLE ---------
try {
let table = $('table.table_recap').DataTable(
{
@@ -217,25 +212,7 @@ $(function () {
],
dom: 'Bfrtip',
- buttons: [
- {
- extend: 'copyHtml5',
- text: 'Copier',
- exportOptions: { orthogonal: 'export' }
- },
- {
- extend: 'excelHtml5',
- // footer: true, // ne fonctionne pas ?
- exportOptions: { orthogonal: 'export' },
- title: document.querySelector('table.table_recap').dataset.filename
- },
- {
- extend: 'collection',
- text: 'Colonnes affichées',
- autoClose: true,
- buttons: buttons,
- },
- ],
+ buttons: buttons,
"drawCallback": function (settings) {
// permet de conserver l'ordre de tri des colonnes
let order_info = JSON.stringify($('table.table_recap').DataTable().order());
diff --git a/app/tables/jury_recap.py b/app/tables/jury_recap.py
index 67dceebf4..db8497d3c 100644
--- a/app/tables/jury_recap.py
+++ b/app/tables/jury_recap.py
@@ -182,24 +182,24 @@ class RowJury(RowRecap):
# table recap standard (mais avec group différent)
super().add_ue_cols(ue, ue_status, col_group=col_group or "col_ue")
dues = self.table.res.get_etud_decision_ues(self.etud.id)
- if not dues:
- return
- due = dues.get(ue.id)
- if not due:
- return
+ due = dues.get(ue.id) if dues else None
+
col_id = f"moy_ue_{ue.id}_code"
+ title = (
+ f"""{ue.acronyme} enregistrée le {due['event_date']}, {
+ (due["ects"] or 0):.3g} ECTS."""
+ if due
+ else """pas de décision"""
+ )
self.add_cell(
col_id,
"", # titre vide
- due["code"],
- raw_content=due["code"],
+ due["code"] if due else "",
+ raw_content=due["code"] if due else "",
group="col_ue",
classes=["recorded_code"],
column_classes={"col_jury", "col_ue_code"},
- target_attrs={
- "title": f"""enregistrée le {due['event_date']}, {
- (due["ects"] or 0):.3g} ECTS."""
- },
+ target_attrs={"title": title},
)
def add_rcue_cols(self, dec_rcue: DecisionsProposeesRCUE):
diff --git a/app/tables/recap.py b/app/tables/recap.py
index 26a911f87..12f0fcc74 100644
--- a/app/tables/recap.py
+++ b/app/tables/recap.py
@@ -82,6 +82,7 @@ class TableRecap(tb.Table):
if res.formsemestre.etuds_inscriptions: # table non vide
# Fixe l'ordre des groupes de colonnes communs:
groups = [
+ "etud_codes",
"rang",
"identite_court",
"identite_detail",