diff --git a/app/__init__.py b/app/__init__.py index 976908844..aab9ef3f5 100755 --- a/app/__init__.py +++ b/app/__init__.py @@ -353,8 +353,7 @@ def create_app(config_class=DevConfig): app.jinja_env.autoescape = select_autoescape(default_for_string=True, default=True) app.jinja_env.trim_blocks = True app.jinja_env.lstrip_blocks = True - # previously in Flask-Bootstrap: - app.jinja_env.globals["bootstrap_is_hidden_field"] = lambda field: isinstance( + app.jinja_env.globals["is_hidden_field"] = lambda field: isinstance( field, HiddenField ) diff --git a/app/forms/main/config_logos.py b/app/forms/main/config_logos.py index 31f8bc6ff..bd88618c8 100644 --- a/app/forms/main/config_logos.py +++ b/app/forms/main/config_logos.py @@ -39,15 +39,13 @@ from wtforms import ValidationError from wtforms.fields.simple import StringField, HiddenField from app.models import Departement -from app.scodoc import sco_logos, html_sco_header +from app.scodoc import sco_logos from app.scodoc import sco_utils as scu from app.scodoc.sco_config_actions import LogoInsert from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_logos import find_logo -CSSSTYLES = html_sco_header.BOOTSTRAP_CSS -JAVASCRIPTS = html_sco_header.BOOTSTRAP_JS # class ItemForm(FlaskForm): # """Unused Generic class to document common behavior for classes @@ -367,6 +365,7 @@ def _make_data(modele): class LogosConfigurationForm(FlaskForm): "Panneau de configuration des logos" + depts = FieldList(FormField(DeptForm)) def __init__(self, *args, **kwargs): diff --git a/app/scodoc/TrivialFormulator.py b/app/scodoc/TrivialFormulator.py index cbabc42d5..b15255105 100644 --- a/app/scodoc/TrivialFormulator.py +++ b/app/scodoc/TrivialFormulator.py @@ -40,6 +40,7 @@ def TrivialFormulator( submitbuttonattributes=None, top_buttons=False, # place buttons at top of form bottom_buttons=True, # buttons after form + html_head_markup="", html_foot_markup="", readonly=False, is_submitted=False, @@ -116,6 +117,7 @@ def TrivialFormulator( submitbuttonattributes=submitbuttonattributes or [], top_buttons=top_buttons, bottom_buttons=bottom_buttons, + html_head_markup=html_head_markup, html_foot_markup=html_foot_markup, readonly=readonly, is_submitted=is_submitted, @@ -152,6 +154,7 @@ class TF(object): submitbuttonattributes=None, top_buttons=False, # place buttons at top of form bottom_buttons=True, # buttons after form + html_head_markup="", # html snippet put at the beginning, just before the table html_foot_markup="", # html snippet put at the end, just after the table readonly=False, is_submitted=False, @@ -178,6 +181,7 @@ class TF(object): self.submitbuttonattributes = submitbuttonattributes or [] self.top_buttons = top_buttons self.bottom_buttons = bottom_buttons + self.html_head_markup = html_head_markup self.html_foot_markup = html_foot_markup self.title = title self.after_table = after_table @@ -425,22 +429,15 @@ class TF(object): hiddenitemtemplate = "%(elem)s" separatortemplate = '%(label)s' # ---- build form - buttons_markup = "" + buttons_markup = """
""" if self.submitbutton: - buttons_markup += ( - '' - % ( - self.formid, - self.formid, - self.submitlabel, - " ".join(self.submitbuttonattributes), - ) - ) + buttons_markup += f"""""" if self.cancelbutton: - buttons_markup += ( - ' ' - % (self.formid, self.formid, self.cancelbutton) - ) + buttons_markup += f""" """ + buttons_markup += "
" R = [] suggest_js = [] @@ -476,6 +473,7 @@ class TF(object): if self.top_buttons: R.append(buttons_markup + "

") R.append(self.before_table.format(title=self.title)) + R.append(self.html_head_markup) R.append('') for field, descr in self.formdescription: if descr.get("readonly", False): @@ -803,8 +801,10 @@ var {field}_as = new bsn.AutoSuggest('{field}', {field}_opts); } // Selections etendues avec shift (use jquery.field) - $('input[name="tf-checked:list"]').createCheckboxRange(); - """ + window.onload = function() { + $('input[name="tf-checked:list"]').createCheckboxRange(); + } + """ ) R.append("") return R diff --git a/app/scodoc/html_sco_header.py b/app/scodoc/html_sco_header.py index de0dd2d01..2d2ad4c6a 100644 --- a/app/scodoc/html_sco_header.py +++ b/app/scodoc/html_sco_header.py @@ -26,8 +26,3 @@ ############################################################################## """Legacy constants (TODO: remove)""" - - -# Some constants: -BOOTSTRAP_JS = ["libjs/bootstrap/js/bootstrap.min.js", "libjs/purl.js"] -BOOTSTRAP_CSS = ["libjs/bootstrap/css/bootstrap.min.css"] diff --git a/app/scodoc/sco_archives_formsemestre.py b/app/scodoc/sco_archives_formsemestre.py index 2365e1b77..31548bcd6 100644 --- a/app/scodoc/sco_archives_formsemestre.py +++ b/app/scodoc/sco_archives_formsemestre.py @@ -289,7 +289,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement. ] menu_choix_groupe = ( """
Groupes d'étudiants à lister: """ - + sco_groups_view.menu_groups_choice(groups_infos) + + sco_groups_view.menu_groups_choice(groups_infos, submit_on_change=True) + """(pour les PV et lettres)
""" ) @@ -307,8 +307,6 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement. return render_template( "sco_page.j2", title="Archiver les PV et résultats", - javascripts=sco_groups_view.JAVASCRIPTS, - cssstyles=sco_groups_view.CSSSTYLES, content="

Archiver les PV et résultats du semestre

" + "\n".join(H) + "\n" diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index e24affef9..48e1c90ac 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -1059,10 +1059,8 @@ du programme" (menu "Semestre") si vous avez un semestre en cours); "sco_page_dept.j2", content="".join(H), page_title=f"Formation {formation.acronyme} v{formation.version}", - cssstyles=html_sco_header.BOOTSTRAP_CSS - + ["libjs/jQuery-tagEditor/jquery.tag-editor.css", "css/ue_table.css"], - javascripts=html_sco_header.BOOTSTRAP_JS - + [ + cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css", "css/ue_table.css"], + javascripts=[ "libjs/jinplace-1.2.1.min.js", "js/ue_list.js", "js/edit_ue.js", @@ -1130,9 +1128,7 @@ def _ue_table_ues( scodoc_dept=g.scodoc_dept, ue_id=ue["ue_id"], ) - ue[ - "code_apogee_str" - ] = f""", Apo: { ue["code_apogee"] or "" diff --git a/app/scodoc/sco_evaluations.py b/app/scodoc/sco_evaluations.py index 400729705..9c5fad6d7 100644 --- a/app/scodoc/sco_evaluations.py +++ b/app/scodoc/sco_evaluations.py @@ -732,7 +732,9 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True) H.append( f""" saisie des notes """ ) diff --git a/app/scodoc/sco_export_results.py b/app/scodoc/sco_export_results.py index c305f4340..b372c72c0 100644 --- a/app/scodoc/sco_export_results.py +++ b/app/scodoc/sco_export_results.py @@ -309,8 +309,7 @@ def scodoc_table_results( return render_template( "sco_page_dept.j2", title="Export résultats", - javascripts=html_sco_header.BOOTSTRAP_JS + ["js/export_results.js"], - cssstyles=html_sco_header.BOOTSTRAP_CSS, + javascripts=["js/export_results.js"], content="\n".join(H), ) diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py index 26b30918f..775e48aca 100644 --- a/app/scodoc/sco_groups_view.py +++ b/app/scodoc/sco_groups_view.py @@ -57,13 +57,6 @@ from app.scodoc.gen_tables import GenTable from app.scodoc.sco_exceptions import ScoValueError, ScoPermissionDenied from app.scodoc.sco_permissions import Permission -JAVASCRIPTS = html_sco_header.BOOTSTRAP_JS + [ - "js/groups_view.js", - "js/multi-select.js", -] - -CSSSTYLES = html_sco_header.BOOTSTRAP_CSS - # view def groups_lists( diff --git a/app/scodoc/sco_moduleimpl_status.py b/app/scodoc/sco_moduleimpl_status.py index 139081f19..ed1e256d2 100644 --- a/app/scodoc/sco_moduleimpl_status.py +++ b/app/scodoc/sco_moduleimpl_status.py @@ -72,7 +72,7 @@ def moduleimpl_evaluation_menu(evaluation: Evaluation, nbnotes: int = 0) -> str: menu_eval = [ { "title": "Saisir les notes", - "endpoint": "notes.saisie_notes", + "endpoint": "notes.form_saisie_notes", "args": { "evaluation_id": evaluation_id, }, @@ -745,7 +745,7 @@ def _ligne_evaluation( ) if can_edit_notes: H.append( - f"""{scu.icontag("notes_img", alt="saisie notes", title="Saisie des notes")}""" ) @@ -824,7 +824,7 @@ def _ligne_evaluation( ) else: H.append( - f"""saisir notes """ @@ -880,7 +880,7 @@ def _ligne_evaluation( H.append("""[""") if can_edit_notes: H.append( - f"""incomplet : terminer saisie]""" @@ -891,9 +891,9 @@ def _ligne_evaluation( H.append("""  """) if can_edit_notes: H.append( - f"""""" ) H.append("pas de notes") diff --git a/app/scodoc/sco_pv_forms.py b/app/scodoc/sco_pv_forms.py index 02521cacf..ce8e97f99 100644 --- a/app/scodoc/sco_pv_forms.py +++ b/app/scodoc/sco_pv_forms.py @@ -50,6 +50,7 @@ from app.scodoc import sco_pdf from app.scodoc import sco_preferences from app.scodoc import sco_pv_pdf from app.scodoc import sco_pv_lettres_inviduelles +from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.gen_tables import GenTable from app.scodoc.codes_cursus import NO_SEMESTRE_ID from app.scodoc.sco_pdf import PDFLOCK @@ -336,12 +337,20 @@ def formsemestre_pvjury(formsemestre_id, fmt="html", publish=True): # --------------------------------------------------------------------------- -def formsemestre_pvjury_pdf(formsemestre_id, group_ids: list[int] = None, etudid=None): - """Generation PV jury en PDF: saisie des paramètres - Si etudid, PV pour un seul etudiant. Sinon, tout les inscrits au groupe indiqué. +def formsemestre_pvjury_pdf(formsemestre_id, etudid=None): + """Génération PV jury en PDF: saisie des paramètres + Si etudid, PV pour un seul etudiant. + Sinon, tout les inscrits au(x) groupe(s) indiqué(s). """ - group_ids = group_ids or [] - formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) + if request.method == "POST": + group_ids = request.form.getlist("group_ids") + else: + group_ids = request.args.getlist("group_ids") + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc + formsemestre: FormSemestre = FormSemestre.get_formsemestre(formsemestre_id) # Mise à jour des groupes d'étapes: sco_groups.create_etapes_partition(formsemestre_id) groups_infos = None @@ -361,7 +370,8 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids: list[int] = None, etudid etudids = [m["etudid"] for m in groups_infos.members] H = [ - f"""
Utiliser cette page pour éditer des versions provisoires des PV. + f"""""" ) else: @@ -394,24 +404,28 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids: list[int] = None, etudid submitlabel="Générer document", name="tf", formid="group_selector", - html_foot_markup=menu_choix_groupe, + html_head_markup=menu_choix_groupe, ) if tf[0] == 0: + info_etud = ( + f"""de {etud.nomprenom}""" + if etud + else "" + ) return render_template( "sco_page.j2", title=f"Édition du PV de jury {('de ' + etud.nom_prenom()) if etud else ''}", content=f"""

Édition du PV de jury - de {etud.nomprenom}

""" + {info_etud}""" + "\n".join(H) + "\n" + tf[1] + "\n".join(F), - javascripts=sco_groups_view.JAVASCRIPTS, - cssstyles=sco_groups_view.CSSSTYLES, + javascripts=["js/groups_view.js"], ) - elif tf[0] == -1: + if tf[0] == -1: return flask.redirect( url_for( "notes.formsemestre_pvjury", @@ -419,34 +433,34 @@ def formsemestre_pvjury_pdf(formsemestre_id, group_ids: list[int] = None, etudid formsemestre_id=formsemestre_id, ) ) + + # submit + tf[2]["show_title"] = bool(tf[2]["show_title"]) + tf[2]["anonymous"] = bool(tf[2]["anonymous"]) + try: + PDFLOCK.acquire() + pdfdoc = sco_pv_pdf.pvjury_pdf( + formsemestre, + etudids, + numero_arrete=tf[2]["numero_arrete"], + code_vdi=tf[2]["code_vdi"], + date_commission=tf[2]["date_commission"], + date_jury=tf[2]["date_jury"], + show_title=tf[2]["show_title"], + pv_title_session=tf[2]["pv_title_session"], + pv_title=tf[2]["pv_title"], + with_paragraph_nom=tf[2]["with_paragraph_nom"], + anonymous=tf[2]["anonymous"], + ) + finally: + PDFLOCK.release() + date_iso = time.strftime("%Y-%m-%d") + if groups_infos: + groups_filename = "-" + groups_infos.groups_filename else: - # submit - tf[2]["show_title"] = bool(tf[2]["show_title"]) - tf[2]["anonymous"] = bool(tf[2]["anonymous"]) - try: - PDFLOCK.acquire() - pdfdoc = sco_pv_pdf.pvjury_pdf( - formsemestre, - etudids, - numero_arrete=tf[2]["numero_arrete"], - code_vdi=tf[2]["code_vdi"], - date_commission=tf[2]["date_commission"], - date_jury=tf[2]["date_jury"], - show_title=tf[2]["show_title"], - pv_title_session=tf[2]["pv_title_session"], - pv_title=tf[2]["pv_title"], - with_paragraph_nom=tf[2]["with_paragraph_nom"], - anonymous=tf[2]["anonymous"], - ) - finally: - PDFLOCK.release() - date_iso = time.strftime("%Y-%m-%d") - if groups_infos: - groups_filename = "-" + groups_infos.groups_filename - else: - groups_filename = "" - filename = f"""PV-{formsemestre.titre_num()}{groups_filename}-{date_iso}.pdf""" - return scu.sendPDFFile(pdfdoc, filename) + groups_filename = "" + filename = f"""PV-{formsemestre.titre_num()}{groups_filename}-{date_iso}.pdf""" + return scu.sendPDFFile(pdfdoc, filename) def descrform_pvjury(formsemestre: FormSemestre): @@ -542,9 +556,17 @@ def descrform_pvjury(formsemestre: FormSemestre): ] -def formsemestre_lettres_individuelles(formsemestre_id, group_ids=()): +def formsemestre_lettres_individuelles(formsemestre_id): "Lettres avis jury en PDF" formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) + if request.method == "POST": + group_ids = request.form.getlist("group_ids") + else: + group_ids = request.args.getlist("group_ids") + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc if not group_ids: # tous les inscrits du semestre group_ids = [sco_groups.get_default_group(formsemestre_id)] @@ -556,20 +578,22 @@ def formsemestre_lettres_individuelles(formsemestre_id, group_ids=()): H = [ f"""

Édition des lettres individuelles

-

Utiliser cette page pour éditer des versions provisoires des PV. +

+ Utiliser cette page pour éditer des versions provisoires des PV. Il est recommandé d'archiver les versions définitives: voir cette page

+ >voir cette page +
""", ] descr = descrform_lettres_individuelles() menu_choix_groupe = ( """
Groupes d'étudiants à lister: """ - + sco_groups_view.menu_groups_choice(groups_infos) + + sco_groups_view.menu_groups_choice(groups_infos, submit_on_change=True) + """
""" ) @@ -581,15 +605,14 @@ def formsemestre_lettres_individuelles(formsemestre_id, group_ids=()): submitlabel="Générer document", name="tf", formid="group_selector", - html_foot_markup=menu_choix_groupe, + html_head_markup=menu_choix_groupe, ) if tf[0] == 0: return render_template( "sco_page.j2", title="Édition des lettres individuelles", content="\n".join(H) + "\n" + tf[1], - javascripts=sco_groups_view.JAVASCRIPTS, - cssstyles=sco_groups_view.CSSSTYLES, + javascripts=["js/groups_view.js"], ) elif tf[0] == -1: return flask.redirect( diff --git a/app/scodoc/sco_report.py b/app/scodoc/sco_report.py index 0984c8c3a..f234786ff 100644 --- a/app/scodoc/sco_report.py +++ b/app/scodoc/sco_report.py @@ -296,6 +296,14 @@ def formsemestre_report_counts( sinon liste prédéfinie (voir ci-dessous) """ formsemestre = FormSemestre.get_formsemestre(formsemestre_id) + if request.method == "POST": + group_ids = request.form.getlist("group_ids") + else: + group_ids = request.args.getlist("group_ids") + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc groups_infos = sco_groups_view.DisplayedGroupsInfos( group_ids, formsemestre_id=formsemestre.id, @@ -420,8 +428,7 @@ def formsemestre_report_counts( ] return render_template( "sco_page.j2", - cssstyles=sco_groups_view.CSSSTYLES, - javascripts=sco_groups_view.JAVASCRIPTS, + javascripts=["js/groups_view.js"], title=title, content="\n".join(H), ) @@ -740,7 +747,6 @@ def table_suivi_cohorte( def formsemestre_suivi_cohorte( formsemestre_id, fmt="html", - group_ids: list[int] = None, # si indiqué, ne prend que ces groupes percent=1, bac="", bacspecialite="", @@ -759,6 +765,14 @@ def formsemestre_suivi_cohorte( raise ScoValueError("formsemestre_suivi_cohorte: argument invalide") from exc formsemestre = FormSemestre.get_formsemestre(formsemestre_id) + if request.method == "POST": + group_ids = request.form.getlist("group_ids") + else: + group_ids = request.args.getlist("group_ids") + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc groups_infos = sco_groups_view.DisplayedGroupsInfos( group_ids, formsemestre_id=formsemestre.id, @@ -850,8 +864,7 @@ def formsemestre_suivi_cohorte( ] return render_template( "sco_page.j2", - cssstyles=sco_groups_view.CSSSTYLES, - javascripts=sco_groups_view.JAVASCRIPTS, + javascripts=["js/groups_view.js"], title=tab.page_title, content="\n".join(H), ) @@ -1629,7 +1642,6 @@ def graph_cursus( def formsemestre_graph_cursus( formsemestre_id, - group_ids: list[int] = None, # si indiqué, ne prend que ces groupes fmt="html", only_primo=False, bac="", # selection sur type de bac @@ -1644,6 +1656,15 @@ def formsemestre_graph_cursus( annee_bac = str(annee_bac or "") annee_admission = str(annee_admission or "") formsemestre = FormSemestre.get_formsemestre(formsemestre_id) + if request.method == "POST": + group_ids = request.form.getlist("group_ids") + else: + group_ids = request.args.getlist("group_ids") + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc + groups_infos = sco_groups_view.DisplayedGroupsInfos( group_ids, formsemestre_id=formsemestre.id, @@ -1781,8 +1802,7 @@ def formsemestre_graph_cursus( ] return render_template( "sco_page.j2", - cssstyles=sco_groups_view.CSSSTYLES, - javascripts=sco_groups_view.JAVASCRIPTS, + javascripts=["js/groups_view.js"], page_title=f"Graphe cursus de {sem['titreannee']}", no_sidebar=True, content="\n".join(H), diff --git a/app/scodoc/sco_saisie_excel.py b/app/scodoc/sco_saisie_excel.py index 6aa6a86f9..f46d4a6dc 100644 --- a/app/scodoc/sco_saisie_excel.py +++ b/app/scodoc/sco_saisie_excel.py @@ -68,7 +68,9 @@ from app.views import ScoData FONT_NAME = "Arial" -def excel_feuille_saisie(evaluation: "Evaluation", rows: list[dict]) -> AnyStr: +def excel_feuille_saisie( + evaluation: "Evaluation", rows: list[dict], groups_titles: str = "" +) -> AnyStr: """Génère feuille excel pour saisie des notes dans l'evaluation - evaluation - rows: liste de dict @@ -77,7 +79,9 @@ def excel_feuille_saisie(evaluation: "Evaluation", rows: list[dict]) -> AnyStr: """ ws = ScoExcelSheet("Saisie notes") styles = _build_styles() - nb_lines_titles = _insert_top_title(ws, styles, evaluation=evaluation) + nb_lines_titles = _insert_top_title( + ws, styles, evaluation=evaluation, groups_titles=groups_titles + ) _insert_line_titles( ws, @@ -263,6 +267,7 @@ def _insert_top_title( evaluation: Evaluation | None = None, formsemestre: FormSemestre | None = None, description="", + groups_titles: str = "", ) -> int: """Insère les lignes de titre de la feuille (suivies d'une ligne blanche). Si evaluation, indique son titre. @@ -298,7 +303,7 @@ def _insert_top_title( evaluation.moduleimpl.formsemestre.titre_annee() if evaluation else (formsemestre.titre_annee() if formsemestre else "") - ) + ) + ((" - " + groups_titles) if groups_titles else "") ws.append_single_cell_row( scu.unescape_html(titre_annee), styles["titres"], prefix=[""] ) @@ -372,15 +377,16 @@ def _insert_bottom_help(ws, styles: dict): ) -def feuille_saisie_notes( - evaluation_id, group_ids: list[int] = None -): # TODO ré-écrire et passer dans notes.py +def feuille_saisie_notes(evaluation_id: int): # TODO ré-écrire et passer dans notes.py """Vue: document Excel pour saisie notes dans l'évaluation et les groupes indiqués""" evaluation = Evaluation.get_evaluation(evaluation_id) - group_ids = group_ids or [] + group_ids = request.args.getlist("group_ids") or [] + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc modimpl = evaluation.moduleimpl formsemestre = modimpl.formsemestre - if evaluation.date_debut: indication_date = evaluation.date_debut.date().isoformat() else: @@ -430,7 +436,9 @@ def feuille_saisie_notes( eval_name = f"{evaluation.moduleimpl.module.code}-{indication_date}" filename = f"notes_{eval_name}_{gr_title_filename}" - xls = excel_feuille_saisie(evaluation, rows=rows) + xls = excel_feuille_saisie( + evaluation, rows=rows, groups_titles=groups_infos.groups_titles + ) return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE) @@ -962,9 +970,14 @@ def _get_sheet_evaluations( raise ValueError("_get_sheet_evaluations") -def saisie_notes_tableur(evaluation_id: int, group_ids=()): +def saisie_notes_tableur(evaluation_id: int): """Saisie des notes via un fichier Excel""" - evaluation = Evaluation.query.get_or_404(evaluation_id) + group_ids = request.args.getlist("group_ids") + try: + group_ids = [int(gid) for gid in group_ids] + except ValueError as exc: + raise ScoValueError("group_ids invalide") from exc + evaluation = Evaluation.get_evaluation(evaluation_id) moduleimpl_id = evaluation.moduleimpl.id formsemestre_id = evaluation.moduleimpl.formsemestre_id if not evaluation.moduleimpl.can_edit_notes(current_user): @@ -1004,18 +1017,20 @@ def saisie_notes_tableur(evaluation_id: int, group_ids=()): # Menu choix groupe: H.append("""
""") - H.append(sco_groups_view.form_groups_choice(groups_infos)) + H.append(sco_groups_view.form_groups_choice(groups_infos, submit_on_change=True)) H.append("
") H.append( f"""
Étape 1 : @@ -1085,7 +1100,7 @@ def saisie_notes_tableur(evaluation_id: int, group_ids=()): scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">Charger un autre fichier de notes     - Formulaire de saisie des notes
""" @@ -1113,7 +1128,9 @@ def saisie_notes_tableur(evaluation_id: int, group_ids=()):