From cd1efba06a7abe51582b5c009081c256024cec18 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 9 Feb 2023 15:27:19 +0100 Subject: [PATCH 1/2] Tables recap: front: boutons vis cols --- app/static/css/scodoc.css | 23 ++++ app/static/js/table_recap.js | 229 ++++++++++++++++------------------- app/tables/recap.py | 1 + 3 files changed, 127 insertions(+), 126 deletions(-) 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/recap.py b/app/tables/recap.py index c0f32e546..42107b720 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", From 3dece830702f583c5b51868e98f7959e54fe35e5 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 9 Feb 2023 16:01:56 +0100 Subject: [PATCH 2/2] Fix: ordre cols code UE dans table recap --- app/scodoc/sco_recapcomplet.py | 3 ++- app/tables/jury_recap.py | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) 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/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):