WIP: nouveau tableau recap pour le BUT
This commit is contained in:
parent
b68d43454f
commit
13f55d5190
@ -15,10 +15,12 @@ from app.comp import moy_ue, moy_sem, inscr_mod
|
||||
from app.comp.res_common import NotesTableCompat
|
||||
from app.comp.bonus_spo import BonusSport
|
||||
from app.models import ScoDocSiteConfig
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
from app.models.ues import UniteEns
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc.sco_codes_parcours import UE_SPORT
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
|
||||
class ResultatsSemestreBUT(NotesTableCompat):
|
||||
@ -32,6 +34,10 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
||||
|
||||
def __init__(self, formsemestre):
|
||||
super().__init__(formsemestre)
|
||||
self.modimpl_coefs_df = None
|
||||
"""DataFrame, row UEs(sans bonus), cols modimplid, value coef"""
|
||||
self.sem_cube = None
|
||||
"""ndarray (etuds x modimpl x ue)"""
|
||||
|
||||
if not self.load_cached():
|
||||
t0 = time.time()
|
||||
@ -145,15 +151,228 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
||||
"""
|
||||
return self.modimpl_coefs_df.loc[ue.id].sum()
|
||||
|
||||
def modimpls_in_ue(self, ue_id, etudid) -> list[ModuleImpl]:
|
||||
def modimpls_in_ue(self, ue_id, etudid, with_bonus=True) -> list[ModuleImpl]:
|
||||
"""Liste des modimpl ayant des coefs non nuls vers cette UE
|
||||
et auxquels l'étudiant est inscrit.
|
||||
et auxquels l'étudiant est inscrit. Inclus modules bonus le cas échéant.
|
||||
"""
|
||||
# sert pour l'affichage ou non de l'UE sur le bulletin
|
||||
# sert pour l'affichage ou non de l'UE sur le bulletin et la table recap
|
||||
coefs = self.modimpl_coefs_df # row UE, cols modimpl
|
||||
return [
|
||||
modimpls = [
|
||||
modimpl
|
||||
for modimpl in self.formsemestre.modimpls_sorted
|
||||
if (coefs[modimpl.id][ue_id] != 0)
|
||||
and self.modimpl_inscr_df[modimpl.id][etudid]
|
||||
]
|
||||
if not with_bonus:
|
||||
return [
|
||||
modimpl for modimpl in modimpls if modimpl.module.ue.type != UE_SPORT
|
||||
]
|
||||
return modimpls
|
||||
|
||||
def get_table_moyennes_triees(self, convert_values=False) -> list:
|
||||
"""Result: tuple avec
|
||||
- rows: liste de dicts { column_id : value }
|
||||
- titles: { column_id : title }
|
||||
- columns_ids: (liste des id de colonnes)
|
||||
|
||||
. Si convert_values, transforme les notes en chaines ("12.34").
|
||||
Les colonnes générées sont:
|
||||
etudid
|
||||
rang : rang indicatif (basé sur moy gen)
|
||||
moy_gen : moy gen indicative
|
||||
moy_ue_<ue_id>, ..., les moyennes d'UE
|
||||
moy_res_<modimpl_id>_<ue_id>, ... les moyennes de ressources dans l'UE
|
||||
moy_sae_<modimpl_id>_<ue_id>, ... les moyennes de SAE dans l'UE
|
||||
|
||||
On ajoute aussi des attributs:
|
||||
- pour les lignes:
|
||||
_css_row_class (inutilisé pour le monent)
|
||||
_<column_id>_class classe css:
|
||||
- la moyenne générale a la classe col_moy_gen
|
||||
- les colonnes SAE ont la classe col_sae
|
||||
- les colonnes Resources ont la classe col_res
|
||||
- les colonnes d'UE ont la classe col_ue
|
||||
- les colonnes de modules (SAE ou res.) d'une UE ont la classe mod_ue_<ue_id>
|
||||
_<column_id>_order : clé de tri
|
||||
"""
|
||||
|
||||
def fmt_note(x):
|
||||
return scu.fmt_note(x) if convert_values else x
|
||||
|
||||
barre_moy = (
|
||||
self.formsemestre.formation.get_parcours().BARRE_MOY - scu.NOTES_TOLERANCE
|
||||
)
|
||||
barre_valid_ue = self.formsemestre.formation.get_parcours().NOTES_BARRE_VALID_UE
|
||||
NO_NOTE = "-" # contenu des cellules sans notes
|
||||
rows = []
|
||||
titles = {"rang": "Rg"} # column_id : title
|
||||
|
||||
def add_cell(
|
||||
row: dict, col_id: str, title: str, content: str, classes: str = ""
|
||||
):
|
||||
"Add a row to our table. classes is a list of css class names"
|
||||
row[col_id] = content
|
||||
if classes:
|
||||
row[f"_{col_id}_class"] = classes
|
||||
if not col_id in titles:
|
||||
titles[col_id] = title
|
||||
if classes:
|
||||
titles[f"_{col_id}_class"] = classes
|
||||
|
||||
etuds_inscriptions = self.formsemestre.etuds_inscriptions
|
||||
ues = self.formsemestre.query_ues(with_sport=True) # avec bonus
|
||||
modimpl_ids = set() # modimpl effectivement présents dans la table
|
||||
for etudid in etuds_inscriptions:
|
||||
etud = Identite.query.get(etudid)
|
||||
row = {"etudid": etudid}
|
||||
# --- Rang
|
||||
add_cell(row, "rang", "Rg", self.etud_moy_gen_ranks[etudid], "rang")
|
||||
row["_rang_order"] = f"{self.etud_moy_gen_ranks_int[etudid]:05d}"
|
||||
# --- Identité étudiant
|
||||
add_cell(row, "civilite_str", "Civ.", etud.civilite_str, "identite_detail")
|
||||
add_cell(row, "nom_disp", "Nom", etud.nom_disp(), "identite_detail")
|
||||
add_cell(row, "prenom", "Prénom", etud.prenom, "identite_detail")
|
||||
add_cell(row, "nom_short", "Nom", etud.nom_short, "identite_court")
|
||||
# --- Moyenne générale
|
||||
moy_gen = self.etud_moy_gen.get(etudid, False)
|
||||
note_class = ""
|
||||
if moy_gen is False:
|
||||
moy_gen = NO_NOTE
|
||||
elif isinstance(moy_gen, float) and moy_gen < barre_moy:
|
||||
note_class = " moy_inf"
|
||||
add_cell(
|
||||
row,
|
||||
"moy_gen",
|
||||
"Moy",
|
||||
fmt_note(moy_gen),
|
||||
"col_moy_gen" + note_class,
|
||||
)
|
||||
# --- Moyenne d'UE
|
||||
for ue in [ue for ue in ues if ue.type != UE_SPORT]:
|
||||
ue_status = self.get_etud_ue_status(etudid, ue.id)
|
||||
if ue_status is not None:
|
||||
col_id = f"moy_ue_{ue.id}"
|
||||
val = ue_status["moy"]
|
||||
note_class = ""
|
||||
if isinstance(val, float):
|
||||
if val < barre_moy:
|
||||
note_class = " moy_inf"
|
||||
elif val >= barre_valid_ue:
|
||||
note_class = " moy_ue_valid"
|
||||
add_cell(
|
||||
row,
|
||||
col_id,
|
||||
ue.acronyme,
|
||||
fmt_note(val),
|
||||
"col_ue" + note_class,
|
||||
)
|
||||
# Les moyennes des ressources et SAÉs dans cette UE
|
||||
for modimpl in self.modimpls_in_ue(ue.id, etudid, with_bonus=False):
|
||||
if ue_status["is_capitalized"]:
|
||||
val = "-c-"
|
||||
else:
|
||||
modimpl_results = self.modimpls_results.get(modimpl.id)
|
||||
if modimpl_results: # pas bonus
|
||||
moys_vers_ue = modimpl_results.etuds_moy_module.get(
|
||||
ue.id
|
||||
)
|
||||
val = (
|
||||
moys_vers_ue.get(etudid, "?")
|
||||
if moys_vers_ue is not None
|
||||
else ""
|
||||
)
|
||||
else:
|
||||
val = ""
|
||||
|
||||
col_id = (
|
||||
f"moy_{modimpl.module.type_abbrv()}_{modimpl.id}_{ue.id}"
|
||||
)
|
||||
add_cell(
|
||||
row,
|
||||
col_id,
|
||||
modimpl.module.code,
|
||||
fmt_note(val),
|
||||
# class col_res mod_ue_123
|
||||
f"col_{modimpl.module.type_abbrv()} mod_ue_{ue.id}",
|
||||
)
|
||||
modimpl_ids.add(modimpl.id)
|
||||
|
||||
rows.append(row)
|
||||
|
||||
# tri par rang croissant
|
||||
rows.sort(key=lambda e: e["_rang_order"])
|
||||
|
||||
# INFOS POUR FOOTER
|
||||
bottom_infos = self._bottom_infos(
|
||||
[ue for ue in ues if ue.type != UE_SPORT], modimpl_ids, fmt_note
|
||||
)
|
||||
|
||||
# --- TABLE FOOTER: ECTS, moyennes, min, max...
|
||||
footer_rows = []
|
||||
for bottom_line in bottom_infos:
|
||||
row = bottom_infos[bottom_line]
|
||||
# Cases vides à styler:
|
||||
row["moy_gen"] = row.get("moy_gen", "")
|
||||
row["_moy_gen_class"] = "col_moy_gen"
|
||||
# titre de la ligne:
|
||||
row["nom_disp"] = row["nom_short"] = bottom_line.capitalize()
|
||||
row["_tr_class"] = bottom_line.lower()
|
||||
footer_rows.append(row)
|
||||
return (
|
||||
rows,
|
||||
footer_rows,
|
||||
titles,
|
||||
[title for title in titles if not title.startswith("_")],
|
||||
)
|
||||
|
||||
def _bottom_infos(self, ues, modimpl_ids: set, fmt_note) -> dict:
|
||||
"""Les informations à mettre en bas de la table: min, max, moy, ECTS"""
|
||||
bottom_infos = { # { key : row } avec key = min, max, moy, coef
|
||||
"min": {},
|
||||
"max": {},
|
||||
"moy": {},
|
||||
"coef": {},
|
||||
}
|
||||
# --- ECTS
|
||||
row = {}
|
||||
for ue in ues:
|
||||
row[f"moy_ue_{ue.id}"] = ue.ects
|
||||
row[f"_moy_ue_{ue.id}_class"] = "col_ue"
|
||||
# style cases vides pour borders verticales
|
||||
bottom_infos["coef"][f"moy_ue_{ue.id}"] = ""
|
||||
bottom_infos["coef"][f"_moy_ue_{ue.id}_class"] = "col_ue"
|
||||
row["moy_gen"] = sum([ue.ects or 0 for ue in ues if ue.type != UE_SPORT])
|
||||
row["_moy_gen_class"] = "col_moy_gen"
|
||||
bottom_infos["ects"] = row
|
||||
|
||||
# --- MIN, MAX, MOY
|
||||
row_min, row_max, row_moy = {}, {}, {}
|
||||
row_min["moy_gen"] = fmt_note(self.etud_moy_gen.min())
|
||||
row_max["moy_gen"] = fmt_note(self.etud_moy_gen.max())
|
||||
row_moy["moy_gen"] = fmt_note(self.etud_moy_gen.mean())
|
||||
for ue in [ue for ue in ues if ue.type != UE_SPORT]:
|
||||
col_id = f"moy_ue_{ue.id}"
|
||||
row_min[col_id] = fmt_note(self.etud_moy_ue[ue.id].min())
|
||||
row_max[col_id] = fmt_note(self.etud_moy_ue[ue.id].max())
|
||||
row_moy[col_id] = fmt_note(self.etud_moy_ue[ue.id].mean())
|
||||
row_min[f"_{col_id}_class"] = "col_ue"
|
||||
row_max[f"_{col_id}_class"] = "col_ue"
|
||||
row_moy[f"_{col_id}_class"] = "col_ue"
|
||||
|
||||
for modimpl in self.formsemestre.modimpls_sorted:
|
||||
if modimpl.id in modimpl_ids:
|
||||
col_id = f"moy_{modimpl.module.type_abbrv()}_{modimpl.id}_{ue.id}"
|
||||
bottom_infos["coef"][col_id] = fmt_note(
|
||||
self.modimpl_coefs_df[modimpl.id][ue.id]
|
||||
)
|
||||
i = self.modimpl_coefs_df.columns.get_loc(modimpl.id)
|
||||
j = self.modimpl_coefs_df.index.get_loc(ue.id)
|
||||
notes = self.sem_cube[:, i, j]
|
||||
row_min[col_id] = fmt_note(np.nanmin(notes))
|
||||
row_max[col_id] = fmt_note(np.nanmax(notes))
|
||||
row_moy[col_id] = fmt_note(np.nanmean(notes))
|
||||
|
||||
bottom_infos["min"] = row_min
|
||||
bottom_infos["max"] = row_max
|
||||
bottom_infos["moy"] = row_moy
|
||||
return bottom_infos
|
||||
|
@ -123,6 +123,11 @@ class Identite(db.Model):
|
||||
r.append("-".join([x.lower().capitalize() for x in fields]))
|
||||
return " ".join(r)
|
||||
|
||||
@property
|
||||
def nom_short(self):
|
||||
"Nom et début du prénom pour table recap: 'DUPONT Pi.'"
|
||||
return f"{(self.nom_usuel or self.nom or '?').upper()} {(self.prenom or '')[:2].capitalize()}."
|
||||
|
||||
@cached_property
|
||||
def sort_key(self) -> tuple:
|
||||
"clé pour tris par ordre alphabétique"
|
||||
|
@ -33,7 +33,7 @@ class Module(db.Model):
|
||||
numero = db.Column(db.Integer) # ordre de présentation
|
||||
# id de l'element pedagogique Apogee correspondant:
|
||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
||||
# Type: ModuleType.STANDARD, MALUS, RESSOURCE, SAE (enum)
|
||||
module_type = db.Column(db.Integer, nullable=False, default=0, server_default="0")
|
||||
# Relations:
|
||||
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||
@ -76,6 +76,11 @@ class Module(db.Model):
|
||||
def type_name(self):
|
||||
return scu.MODULE_TYPE_NAMES[self.module_type]
|
||||
|
||||
def type_abbrv(self):
|
||||
""" "mod", "malus", "res", "sae"
|
||||
(utilisées pour style css)"""
|
||||
return scu.ModuleType.get_abbrev(self.module_type)
|
||||
|
||||
def set_ue_coef(self, ue, coef: float) -> None:
|
||||
"""Set coef module vers cette UE"""
|
||||
self.update_ue_coef_dict({ue.id: coef})
|
||||
|
@ -4,7 +4,6 @@
|
||||
from app import db
|
||||
from app.models import APO_CODE_STR_LEN
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.scodoc import notesdb as ndb
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@ from flask import make_response, url_for
|
||||
from app import log
|
||||
from app.but import bulletin_but
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_but import ResultatsSemestreBUT
|
||||
from app.comp.res_common import NotesTableCompat
|
||||
from app.models import FormSemestre
|
||||
from app.models.etudiants import Identite
|
||||
@ -108,7 +109,7 @@ def formsemestre_recapcomplet(
|
||||
page_title="Récapitulatif",
|
||||
no_side_bar=True,
|
||||
init_qtip=True,
|
||||
javascripts=["js/etud_info.js"],
|
||||
javascripts=["js/etud_info.js", "js/table_recap.js"],
|
||||
),
|
||||
sco_formsemestre_status.formsemestre_status_head(
|
||||
formsemestre_id=formsemestre_id
|
||||
@ -223,6 +224,14 @@ def do_formsemestre_recapcomplet(
|
||||
force_publishing=True,
|
||||
):
|
||||
"""Calcule et renvoie le tableau récapitulatif."""
|
||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
if (
|
||||
formsemestre.formation.is_apc()
|
||||
and format not in ("xml", "json")
|
||||
and not modejury
|
||||
):
|
||||
data, filename = make_formsemestre_recapcomplet_apc(formsemestre, format=format)
|
||||
else:
|
||||
data, filename, format = make_formsemestre_recapcomplet(
|
||||
formsemestre_id=formsemestre_id,
|
||||
format=format,
|
||||
@ -236,6 +245,7 @@ def do_formsemestre_recapcomplet(
|
||||
rank_partition_id=rank_partition_id,
|
||||
force_publishing=force_publishing,
|
||||
)
|
||||
# ---
|
||||
if format == "xml" or format == "html":
|
||||
return data
|
||||
elif format == "csv":
|
||||
@ -1004,3 +1014,59 @@ def formsemestres_bulletins(annee_scolaire):
|
||||
jslist.append(J)
|
||||
|
||||
return scu.sendJSON(jslist)
|
||||
|
||||
|
||||
def _gen_cell(key: str, row: dict, elt="td"):
|
||||
"html table cell"
|
||||
klass = row.get(f"_{key}_class")
|
||||
attrs = f'class="{klass}"' if klass else ""
|
||||
order = row.get("_{key}_order")
|
||||
if order:
|
||||
attrs += f' data-order="{order}"'
|
||||
return f'<{elt} {attrs}>{row.get(key, "")}</{elt}>'
|
||||
|
||||
|
||||
def _gen_row(keys: list[str], row, elt="td"):
|
||||
klass = row.get("_tr_class")
|
||||
tr_class = f'class="{klass}"' if klass else ""
|
||||
return f'<tr {tr_class}>{"".join([_gen_cell(key, row, elt) for key in keys])}</tr>'
|
||||
|
||||
|
||||
def make_formsemestre_recapcomplet_apc(formsemestre: FormSemestre, format="html"):
|
||||
"""Construit table recap pour le BUT
|
||||
Return: data, filename
|
||||
"""
|
||||
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
||||
rows, footer_rows, titles, column_ids = res.get_table_moyennes_triees(
|
||||
convert_values=True
|
||||
)
|
||||
H = ['<div class="table_recap"><table class="table_recap">']
|
||||
# header
|
||||
H.append(
|
||||
f"""
|
||||
<thead>
|
||||
{_gen_row(column_ids, titles, "th")}
|
||||
</thead>
|
||||
"""
|
||||
)
|
||||
# body
|
||||
H.append("<tbody>")
|
||||
for row in rows:
|
||||
H.append(f"{_gen_row(column_ids, row)}\n")
|
||||
H.append("</tbody>\n")
|
||||
# footer
|
||||
H.append("<tfoot>")
|
||||
for row in footer_rows:
|
||||
H.append(f"{_gen_row(column_ids, row)}\n")
|
||||
H.append(
|
||||
f"""
|
||||
{_gen_row(column_ids, titles, "th")}
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
return (
|
||||
"".join(H),
|
||||
f'recap-{formsemestre.titre_num().replace(" ", "_")}-{time.strftime("%d-%m-%Y")}',
|
||||
) # suffix ?
|
||||
|
@ -87,6 +87,19 @@ class ModuleType(IntEnum):
|
||||
RESSOURCE = 2 # BUT
|
||||
SAE = 3 # BUT
|
||||
|
||||
@classmethod
|
||||
def get_abbrev(cls, code) -> str:
|
||||
"""Chaine abregée décrivant le type de module à partir du code integer:
|
||||
"mod", "malus", "res", "sae"
|
||||
(utilisées pour style css)
|
||||
"""
|
||||
return {
|
||||
ModuleType.STANDARD: "mod",
|
||||
ModuleType.MALUS: "malus",
|
||||
ModuleType.RESSOURCE: "res",
|
||||
ModuleType.SAE: "sae",
|
||||
}.get(code, "???")
|
||||
|
||||
|
||||
MODULE_TYPE_NAMES = {
|
||||
ModuleType.STANDARD: "Module",
|
||||
|
@ -3238,3 +3238,45 @@ table.dataTable tr.gt_lastrow th {
|
||||
table.dataTable td.etudinfo, table.dataTable td.group {
|
||||
text-align: left;
|
||||
}
|
||||
/* Nouveau tableau recap */
|
||||
div.table_recap table.table_recap {
|
||||
width: auto;
|
||||
}
|
||||
table.table_recap .identite_court {
|
||||
white-space:nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
table.table_recap .rang {
|
||||
white-space:nowrap;
|
||||
text-align: right;
|
||||
}
|
||||
table.table_recap .col_ue, table.table_recap .col_moy_gen {
|
||||
border-left: 1px solid blue;
|
||||
}
|
||||
table.table_recap tfoot th, table.table_recap thead th {
|
||||
text-align: left;
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
table.table_recap td.moy_inf {
|
||||
font-weight: bold;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
table.table_recap td.moy_ue_valid {
|
||||
font-weight: bold;
|
||||
color: rgb(0,140,0);
|
||||
}
|
||||
table.table_recap tr.ects td {
|
||||
color: rgb(160, 86, 3);
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid blue;
|
||||
}
|
||||
table.table_recap tr.coef td {
|
||||
font-style: italic;
|
||||
color: #9400d3;
|
||||
}
|
||||
table.table_recap tr.coef td, table.table_recap tr.min td,
|
||||
table.table_recap tr.max td, table.table_recap tr.moy td {
|
||||
font-size: 80%;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
67
app/static/js/table_recap.js
Normal file
67
app/static/js/table_recap.js
Normal file
@ -0,0 +1,67 @@
|
||||
// Tableau recap notes
|
||||
$(function () {
|
||||
$(function () {
|
||||
$('table.table_recap').DataTable(
|
||||
{
|
||||
paging: false,
|
||||
searching: true,
|
||||
info: false,
|
||||
autoWidth: false,
|
||||
fixedHeader: {
|
||||
header: true,
|
||||
footer: true
|
||||
},
|
||||
orderCellsTop: true, // cellules ligne 1 pour tri
|
||||
aaSorting: [], // Prevent initial sorting
|
||||
colReorder: true,
|
||||
"columnDefs": [
|
||||
{
|
||||
// cache le détail de l'identité (pas réussi à le faire avec le sélecteur css)
|
||||
"targets": [1, 2, 3], // ".identite_detail",
|
||||
"visible": false,
|
||||
},
|
||||
],
|
||||
dom: 'Bfrtip',
|
||||
buttons: [
|
||||
'copy', 'excel', 'pdf',
|
||||
{
|
||||
extend: 'collection',
|
||||
text: 'Réglages affichage',
|
||||
autoClose: true,
|
||||
buttons: [
|
||||
{
|
||||
name: "toggle_ident",
|
||||
text: "Civ/Nom/Prénom",
|
||||
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.buttons('toggle_ident:name').text(visible ? "Civ/Nom/Prénom" : "Nom");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "toggle_res",
|
||||
text: "Cacher les ressources",
|
||||
action: function (e, dt, node, config) {
|
||||
let visible = dt.columns(".col_res").visible()[0];
|
||||
dt.columns(".col_res").visible(!visible);
|
||||
dt.buttons('toggle_res:name').text(visible ? "Montrer les ressources" : "Cacher les ressources");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "toggle_sae",
|
||||
text: "Cacher les SAÉs",
|
||||
action: function (e, dt, node, config) {
|
||||
let visible = dt.columns(".col_sae").visible()[0];
|
||||
dt.columns(".col_sae").visible(!visible);
|
||||
dt.buttons('toggle_sae:name').text(visible ? "Montrer les SAÉs" : "Cacher les SAÉs");
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.1.86"
|
||||
SCOVERSION = "9.2-86"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user