From 26dcc0db3beafce46ec49b15dde8446e5c60e3e1 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet <emmanuel.viennet@gmail.com> Date: Thu, 22 Aug 2024 22:02:34 +0200 Subject: [PATCH] =?UTF-8?q?Pages=20groupes:=203=20pages=20s=C3=A9par=C3=A9?= =?UTF-8?q?es=20au=20lieu=20des=20tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_archives_etud.py | 2 +- app/scodoc/sco_formsemestre_status.py | 22 +++- app/scodoc/sco_groups_view.py | 112 +++++++++--------- app/scodoc/sco_page_etud.py | 2 +- app/scodoc/sco_trombino.py | 10 +- app/static/js/groups_view.js | 5 - app/templates/formsemestre/groups_feuilles.j2 | 27 +++++ app/templates/formsemestre/groups_lists.j2 | 37 ++++++ app/templates/formsemestre/groups_photos.j2 | 27 +++++ app/templates/formsemestre_header.j2 | 2 +- app/templates/formsemestre_page_title.j2 | 2 +- app/views/scolar.py | 44 ++++++- tests/unit/test_formsemestre.py | 4 +- 13 files changed, 215 insertions(+), 81 deletions(-) create mode 100644 app/templates/formsemestre/groups_feuilles.j2 create mode 100644 app/templates/formsemestre/groups_lists.j2 create mode 100644 app/templates/formsemestre/groups_photos.j2 diff --git a/app/scodoc/sco_archives_etud.py b/app/scodoc/sco_archives_etud.py index b7ff7d32..0067be0a 100644 --- a/app/scodoc/sco_archives_etud.py +++ b/app/scodoc/sco_archives_etud.py @@ -358,7 +358,7 @@ def etudarchive_import_files( unmatched_files=unmatched_files, stored_etud_filename=stored_etud_filename, next_page=url_for( - "scolar.groups_view", + "scolar.groups_feuilles", scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, ), diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 6b5d1a3a..5f3d69ce 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -335,7 +335,7 @@ def formsemestre_status_menubar(formsemestre: FormSemestre | None) -> str: }, { "title": "Exporter table des étudiants", - "endpoint": "scolar.groups_view", + "endpoint": "scolar.groups_lists", "args": { "fmt": "allxls", "group_ids": sco_groups.get_default_group( @@ -354,12 +354,26 @@ def formsemestre_status_menubar(formsemestre: FormSemestre | None) -> str: can_change_groups = formsemestre.can_change_groups() menu_groupes = [ { - "title": "Listes, photos, feuilles...", - "endpoint": "scolar.groups_view", + "title": "Listes des groupes", + "endpoint": "scolar.groups_lists", "args": {"formsemestre_id": formsemestre_id}, "enabled": True, "helpmsg": "Accès aux listes des groupes d'étudiants", }, + { + "title": "Trombinoscopes", + "endpoint": "scolar.groups_photos", + "args": {"formsemestre_id": formsemestre_id}, + "enabled": True, + "helpmsg": "Accès aux photos des groupes d'étudiants", + }, + { + "title": "Assiduité, feuilles d'appel, ...", + "endpoint": "scolar.groups_feuilles", + "args": {"formsemestre_id": formsemestre_id}, + "enabled": True, + "helpmsg": "Accès aux feuilles d'appel des groupes d'étudiants", + }, { "title": "Modifier groupes et partitions", "endpoint": "scolar.partition_editor", @@ -826,7 +840,7 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str: <div class="sem-groups-list"> <div> <a class="stdlink" href="{ - url_for("scolar.groups_view", + url_for("scolar.groups_lists", group_ids=group.id, scodoc_dept=g.scodoc_dept, ) diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py index 2114f20c..d4817ee2 100644 --- a/app/scodoc/sco_groups_view.py +++ b/app/scodoc/sco_groups_view.py @@ -30,12 +30,13 @@ sous forme: de liste html (table exportable), de trombinoscope (exportable en pd """ # Re-ecriture en 2014 (re-organisation de l'interface, modernisation du code) +# Modif en 2024 (9.7/revamp, abandon des tabs bootstrap) import datetime from urllib.parse import parse_qs -from flask import url_for, g, request +from flask import url_for, g, render_template, request from flask_login import current_user from app import db @@ -64,8 +65,8 @@ JAVASCRIPTS = html_sco_header.BOOTSTRAP_JS + [ CSSSTYLES = html_sco_header.BOOTSTRAP_CSS -# view: -def groups_view( +# view +def groups_lists( group_ids=(), fmt="html", with_codes=0, @@ -87,6 +88,7 @@ def groups_view( formsemestre_id est utilisé si aucun groupe selectionné pour construire la liste des groupes. """ + # version sans tabs: juste la liste des étudiants # Informations sur les groupes à afficher: groups_infos = DisplayedGroupsInfos( group_ids, @@ -112,60 +114,58 @@ def groups_view( # - charger tous les etudiants au debut, quels que soient les groupes selectionnés # - ajouter du JS pour modifier les liens (arguments group_ids) quand le menu change - return f""" - { html_sco_header.sco_header( - javascripts=JAVASCRIPTS, - cssstyles=CSSSTYLES - ) - } - <style> - span.warning_unauthorized {{ - color: pink; - font-style: italic; - margin-left: 12px; - }} - </style> - <div id="group-tabs"> - <!-- Menu choix groupe --> - {form_groups_choice(groups_infos, submit_on_change=True)} - <ul class="nav nav-tabs" id="myTab" role="tablist"> - <li class="nav-item" role="presentation"> - <button class="nav-link active" id="tab-listes" data-bs-toggle="tab" data-bs-target="#tab-listes-pane" type="button" role="tab" aria-controls="tab-listes-pane" aria-selected="true">Listes</button> - </li> - <li class="nav-item" role="presentation"> - <button class="nav-link" id="tab-photos" data-bs-toggle="tab" data-bs-target="#tab-photos-pane" type="button" role="tab" aria-controls="tab-photos-pane" aria-selected="true">Photos</button> - </li> - <li class="nav-item" role="presentation"> - <button class="nav-link" id="tab-abs" data-bs-toggle="tab" data-bs-target="#tab-abs-pane" type="button" role="tab" aria-controls="tab-abs-pane" aria-selected="true">Absences et feuilles...</button> - </li> - </ul> - <!-- Tab panes --> - <div class="tab-content" id="myTabContent"> - <div class="tab-pane active show" id="tab-listes-pane" role="tabpanel" aria-labelledby="tab-listes" tabindex="0"> - { - groups_table( - groups_infos=groups_infos, - fmt=fmt, - with_codes=with_codes, - etat=etat, - with_paiement=with_paiement, - with_archives=with_archives, - with_annotations=with_annotations, - with_bourse=with_bourse, - ) - } - </div> - <div class="tab-pane" id="tab-photos-pane" role="tabpanel" aria-labelledby="tab-photos" tabindex="0"> - { tab_photos_html(groups_infos, etat=etat) } - </div> - <div class="tab-pane" id="tab-abs-pane" role="tabpanel" aria-labelledby="tab-abs" tabindex="0"> - { tab_absences_html(groups_infos, etat=etat) } - </div> - </div> - </div> - - { html_sco_header.sco_footer() } + return render_template( + "formsemestre/groups_lists.j2", + form_groups_choice=form_groups_choice(groups_infos, submit_on_change=True), + groups_table=groups_table( + groups_infos=groups_infos, + fmt=fmt, + with_codes=with_codes, + etat=etat, + with_paiement=with_paiement, + with_archives=with_archives, + with_annotations=with_annotations, + with_bourse=with_bourse, + ), + groups_titles=groups_infos.groups_titles, + ) + + +# view +def groups_photos(group_ids=(), etat=None, formsemestre_id=None): + """Affichage des photos des étudiants (trombi) des groupes indiqués + group_ids: liste de group_id + formsemestre_id est utilisé si aucun groupe selectionné pour construire la liste des groupes. + """ + groups_infos = DisplayedGroupsInfos( + group_ids, + formsemestre_id=formsemestre_id, + select_all_when_unspecified=True, + ) + return render_template( + "formsemestre/groups_photos.j2", + form_groups_choice=form_groups_choice(groups_infos, submit_on_change=True), + tab_photos_html=tab_photos_html(groups_infos, etat=etat), + groups_titles=groups_infos.groups_titles, + ) + + +def groups_feuilles(group_ids=(), etat=None, formsemestre_id=None): + """Affichage des feuilles d'appel des groupes indiqués + group_ids: liste de group_id + formsemestre_id est utilisé si aucun groupe selectionné pour construire la liste des groupes. """ + groups_infos = DisplayedGroupsInfos( + group_ids, + formsemestre_id=formsemestre_id, + select_all_when_unspecified=True, + ) + return render_template( + "formsemestre/groups_feuilles.j2", + form_groups_choice=form_groups_choice(groups_infos, submit_on_change=True), + tab_absences_html=tab_absences_html(groups_infos, etat=etat), + groups_titles=groups_infos.groups_titles, + ) def form_groups_choice( diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py index c2f604c3..5250af77 100644 --- a/app/scodoc/sco_page_etud.py +++ b/app/scodoc/sco_page_etud.py @@ -254,7 +254,7 @@ def fiche_etud(etudid=None): grlinks.append( f"""<a class="discretelink" href="{ - url_for('scolar.groups_view', + url_for('scolar.groups_lists', scodoc_dept=g.scodoc_dept, group_ids=partition['group_id']) }" title="Liste du groupe {gr_name}">{gr_name}</a> """ diff --git a/app/scodoc/sco_trombino.py b/app/scodoc/sco_trombino.py index 7431609b..3ed60ec1 100644 --- a/app/scodoc/sco_trombino.py +++ b/app/scodoc/sco_trombino.py @@ -208,8 +208,7 @@ def check_local_photos_availability(groups_infos, fmt=""): >exporter seulement les photos existantes</a>""", dest_url="trombino", OK="Exporter seulement les photos existantes", - cancel_url="groups_view?curtab=tab-photos&" - + groups_infos.groups_query_args, + cancel_url="groups_photos?" + groups_infos.groups_query_args, parameters=parameters, ), ) @@ -249,7 +248,7 @@ def trombino_copy_photos(group_ids=None, dialog_confirmed=False): "Copy photos from portal to ScoDoc (overwriting local copy)" group_ids = [] if group_ids is None else group_ids groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids) - back_url = "groups_view?%s&curtab=tab-photos" % groups_infos.groups_query_args + back_url = "groups_photos?" + str(groups_infos.groups_query_args) portal_url = sco_portal_apogee.get_portal_url() header = html_sco_header.sco_header(page_title="Chargement des photos") @@ -504,7 +503,7 @@ def photos_import_files_form(group_ids=()): if not group_ids: raise ScoValueError("paramètre manquant !") groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids) - back_url = f"groups_view?{groups_infos.groups_query_args}&curtab=tab-photos" + back_url = f"groups_photos?{groups_infos.groups_query_args}" H = [ html_sco_header.sco_header(page_title="Import des photos des étudiants"), @@ -567,10 +566,9 @@ def photos_import_files_form(group_ids=()): unmatched_files=unmatched_files, stored_etud_filename=stored_etud_filename, next_page=url_for( - "scolar.groups_view", + "scolar.groups_photos", scodoc_dept=g.scodoc_dept, formsemestre_id=groups_infos.formsemestre_id, - curtab="tab-photos", ), ) diff --git a/app/static/js/groups_view.js b/app/static/js/groups_view.js index 29517a32..7f16a580 100644 --- a/app/static/js/groups_view.js +++ b/app/static/js/groups_view.js @@ -20,11 +20,6 @@ function groups_view_url() { "formsemestre_id", $("#group_selector")[0].formsemestre_id.value ); - // ajout du tab actif - const tabActif = document.querySelector( - '[role="tab"][aria-selected="true"]' - ).id; - urlParams.set("tab", tabActif); urlParams.delete("group_ids"); // ajout des groupes selectionnes var selected_groups = document.getElementById("group_ids_sel").value; diff --git a/app/templates/formsemestre/groups_feuilles.j2 b/app/templates/formsemestre/groups_feuilles.j2 new file mode 100644 index 00000000..2565ca0f --- /dev/null +++ b/app/templates/formsemestre/groups_feuilles.j2 @@ -0,0 +1,27 @@ +{# Trombinoscope HTML #} + +{% extends "sco_page.j2" %} + + +{% block title %} + Feuilles {{groups_titles}} +{% endblock title %} + + +{% block app_content %} + <div class="pageContent"> + <!-- Menu choix groupe --> + {{form_groups_choice|safe}} + + <div> + {{tab_absences_html|safe}} + </div> + </div> + +{% endblock %} + + +{% block scripts %} + {{ super() }} + <script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script> +{% endblock %} diff --git a/app/templates/formsemestre/groups_lists.j2 b/app/templates/formsemestre/groups_lists.j2 new file mode 100644 index 00000000..eeb0fdd1 --- /dev/null +++ b/app/templates/formsemestre/groups_lists.j2 @@ -0,0 +1,37 @@ +{# Liste des membres d'un ou plusieurs groupes #} + +{% extends "sco_page.j2" %} + +{% block styles %} + {{ super() }} + <style> + span.warning_unauthorized { + color: pink; + font-style: italic; + margin-left: 12px; + } + </style> +{% endblock styles %} + + + +{% block title %} + {{groups_titles}} +{% endblock title %} + +{% block app_content %} + <div class="pageContent"> + <!-- Menu choix groupe --> + {{form_groups_choice|safe}} + + <div> + {{groups_table|safe}} + </div> + </div> +{% endblock %} + + +{% block scripts %} + {{ super() }} + <script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script> +{% endblock %} diff --git a/app/templates/formsemestre/groups_photos.j2 b/app/templates/formsemestre/groups_photos.j2 new file mode 100644 index 00000000..68d1516f --- /dev/null +++ b/app/templates/formsemestre/groups_photos.j2 @@ -0,0 +1,27 @@ +{# Trombinoscope HTML #} + +{% extends "sco_page.j2" %} + + +{% block title %} + Photos {{groups_titles}} +{% endblock title %} + + +{% block app_content %} + <div class="pageContent"> + <!-- Menu choix groupe --> + {{form_groups_choice|safe}} + + <div> + {{tab_photos_html|safe}} + </div> + </div> + +{% endblock %} + + +{% block scripts %} + {{ super() }} + <script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script> +{% endblock %} diff --git a/app/templates/formsemestre_header.j2 b/app/templates/formsemestre_header.j2 index d8d7693e..1e5019a9 100644 --- a/app/templates/formsemestre_header.j2 +++ b/app/templates/formsemestre_header.j2 @@ -21,7 +21,7 @@ </span> <span class="resp"><a title="{{sco.formsemestre.responsables_str(abbrev_prenom=False)}}">{{sco.formsemestre.responsables_str()}}</a></span> - <span class="nbinscrits"><a class="discretelink" href="{{url_for('scolar.groups_view', scodoc_dept=g.scodoc_dept, + <span class="nbinscrits"><a class="discretelink" href="{{url_for('scolar.groups_lists', scodoc_dept=g.scodoc_dept, formsemestre_id=sco.formsemestre.id)}}">{{sco.formsemestre.inscriptions|length}} inscrits</a></span> <span class="lock"> {% if not sco.formsemestre.etat %}<a href="{{url_for('notes.formsemestre_flip_lock', scodoc_dept=g.scodoc_dept, diff --git a/app/templates/formsemestre_page_title.j2 b/app/templates/formsemestre_page_title.j2 index 1d6f4f1f..075faf9b 100644 --- a/app/templates/formsemestre_page_title.j2 +++ b/app/templates/formsemestre_page_title.j2 @@ -17,7 +17,7 @@ au {{formsemestre.date_fin.strftime('%d/%m/%Y')}} ">{{formsemestre.mois_debut()}} - {{formsemestre.mois_fin()}}</a></span><span class="resp"><a title="{{formsemestre.responsables_str(abbrev_prenom=False)}}">{{formsemestre.responsables_str()}}</a></span><span - class="nbinscrits"><a class="discretelink" href="{{url_for('scolar.groups_view', + class="nbinscrits"><a class="discretelink" href="{{url_for('scolar.groups_lists', scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id) }}">{{formsemestre.etuds_inscriptions|length}} inscrits</a></span><span class="lock"> {%-if not formsemestre.etat -%} diff --git a/app/views/scolar.py b/app/views/scolar.py index 60e89d4d..b375b533 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -461,11 +461,11 @@ sco_publish( ) -@bp.route("/groups_view") +@bp.route("/groups_lists") @scodoc -@permission_required_compat_scodoc7(Permission.ScoView) +@permission_required(Permission.ScoView) @scodoc7func -def groups_view( +def groups_lists( group_ids=(), fmt="html", # Options pour listes: @@ -477,10 +477,10 @@ def groups_view( with_bourse=0, formsemestre_id=None, ): - return sco_groups_view.groups_view( + "Listes des étudiants des groupes" + return sco_groups_view.groups_lists( group_ids=group_ids, fmt=fmt, - # Options pour listes: with_codes=with_codes, etat=etat, with_paiement=with_paiement, @@ -491,6 +491,40 @@ def groups_view( ) +@bp.route("/groups_photos") +@scodoc +@permission_required(Permission.ScoView) +@scodoc7func +def groups_photos( + group_ids=(), + etat=None, + formsemestre_id=None, +): + "trombi HTML" + return sco_groups_view.groups_photos( + group_ids=group_ids, + etat=etat, + formsemestre_id=formsemestre_id, + ) + + +@bp.route("/groups_feuilles") +@scodoc +@permission_required(Permission.ScoView) +@scodoc7func +def groups_feuilles( + group_ids=(), + etat=None, + formsemestre_id=None, +): + "Feuilles appel, liens assiduité, etc." + return sco_groups_view.groups_feuilles( + group_ids=group_ids, + etat=etat, + formsemestre_id=formsemestre_id, + ) + + sco_publish( "/export_groups_as_moodle_csv", sco_groups_view.export_groups_as_moodle_csv, diff --git a/tests/unit/test_formsemestre.py b/tests/unit/test_formsemestre.py index e9677c4f..928aae83 100644 --- a/tests/unit/test_formsemestre.py +++ b/tests/unit/test_formsemestre.py @@ -136,7 +136,9 @@ def test_formsemestre_misc_views(test_client): ans = sco_formsemestre_inscriptions.formsemestre_inscrits_ailleurs(formsemestre.id) # ----- MENU GROUPES - ans = call_view(scolar.groups_view, formsemestre.id) + ans = call_view(scolar.groups_lists, formsemestre.id) + ans = call_view(scolar.groups_photos, formsemestre.id) + ans = call_view(scolar.groups_feuilles, formsemestre.id) ans = call_view(scolar.partition_editor, formsemestre.id) ans = sco_groups.edit_partition_form(formsemestre.id) -- GitLab