Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
11 changed files with 311 additions and 370 deletions
Showing only changes of commit ef63e27aed - Show all commits

View File

@ -174,7 +174,7 @@
text-align: start;
top: -40px;
transform: translateX(-50%);
z-index: 2;
z-index: 1;
}
@ -183,7 +183,7 @@
content: "|";
position: absolute;
bottom: -2px;
z-index: 2;
z-index: 1;
}
.mini-timeline-block.creneau {

View File

@ -39,7 +39,7 @@ $(function () {
"Avril",
"May",
"Juin",
"Juilet",
"Juillet",
"Août",
"Septembre",
"Octobre",

View File

@ -1,3 +1,70 @@
{% extends "sco_page.j2" %}
{% block title %}
Bilan assiduité de {{sco.etud.nomprenom}}
{% endblock title %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
<style>
.stats-values-item {
display: flex;
justify-content: space-evenly;
align-items: center;
flex-direction: column;
}
.stats {
border: 1px solid #333;
padding: 5px 2px;
width: fit-content;
}
.stats-values {
display: flex;
justify-content: flex-start;
gap: 15px;
}
.stats-values-item h5 {
font-weight: bold;
text-decoration-line: underline;
}
.stats-values-part {
display: flex;
flex-direction: column;
}
.alerte {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 5px 0;
border-radius: 7px;
background-color: var(--color-error);
}
.alerte.invisible {
display: none;
}
.alerte p {
font-size: larger;
color: whitesmoke;
}
.suppr {
margin: 5px 0;
}
</style>
{% endblock styles %}
{% block app_content %}
{% include "assiduites/widgets/tableau_base.j2" %}
<div class="pageContent">
@ -45,8 +112,13 @@
</div>
{% endblock app_content %}
<script>
{% block scripts %}
{{ super() }}
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
<script>
function stats() {
const dd_val = document.getElementById('stats_date_debut').value;
const df_val = document.getElementById('stats_date_fin').value;
@ -109,7 +181,7 @@
}
const heure = document.createElement('span');
heure.textContent = `${counter[key].total.heure} heure(s)${withJusti(key, "heure")}`;
heure.textContent = `${counter[key].total.heure.toFixed(2)} heure(s)${withJusti(key, "heure")}`;
const demi = document.createElement('span');
demi.textContent = `${counter[key].total.demi} demi-journée(s)${withJusti(key, "demi")}`;
@ -238,59 +310,6 @@
})
</script>
<style>
.stats-values-item {
display: flex;
justify-content: space-evenly;
align-items: center;
flex-direction: column;
}
{% endblock %}
.stats {
border: 1px solid #333;
padding: 5px 2px;
width: fit-content;
}
.stats-values {
display: flex;
justify-content: flex-start;
gap: 15px;
}
.stats-values-item h5 {
font-weight: bold;
text-decoration-line: underline;
}
.stats-values-part {
display: flex;
flex-direction: column;
}
.alerte {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
margin: 5px 0;
border-radius: 7px;
background-color: var(--color-error);
}
.alerte.invisible {
display: none;
}
.alerte p {
font-size: larger;
color: whitesmoke;
}
.suppr {
margin: 5px 0;
}
</style>

View File

@ -1,3 +1,21 @@
{% extends "sco_page.j2" %}
{% block title %}
Assiduité de {{etud.nomprenom}}
{% endblock title %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
{% endblock styles %}
{% block scripts %}
{{ super() }}
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
{% endblock %}
{% block app_content %}
<div class="pageContent">

View File

@ -3,6 +3,26 @@
- TODO : revoir le fonctionnement de cette page (trop lente / complexe)
- Utiliser majoritairement du python
#}
{% extends "sco_page.j2" %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
{% endblock styles %}
{% block title %}
{{title}}
{% endblock title %}
{% block app_content %}
{% include "assiduites/widgets/alert.j2" %}
{% include "assiduites/widgets/prompt.j2" %}
{% include "assiduites/widgets/conflict.j2" %}
{% include "assiduites/widgets/toast.j2" %}
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
<h2>Signalement différé de l'assiduité {{gr |safe}}</h2>
<div class="ue_warning">Attention, cette page utilise des couleurs et conventions différentes
@ -27,7 +47,13 @@
<p>Vous pouvez supprimer une colonne en appuyant sur la croix qui se situe dans le coin haut droit de la colonne.
</p>
</div>
{% endblock app_content %}
{% block scripts %}
{{ super() }}
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
<script>
const etudsDefDem = {{ defdem | safe }}
@ -71,14 +97,5 @@
createColumn();
}
})
</script>
{% include "assiduites/widgets/alert.j2" %}
{% include "assiduites/widgets/prompt.j2" %}
{% include "assiduites/widgets/conflict.j2" %}
{% include "assiduites/widgets/toast.j2" %}
{% endblock scripts %}

View File

@ -1,4 +1,86 @@
{% extends "sco_page.j2" %}
{% block title %}
{{title}}
{% endblock title %}
{% block scripts %}
{{ super() }}
<script src="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.js"></script>
<script src="{{scu.STATIC_DIR}}/libjs/purl.js"></script>
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
<script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script>
<script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
<script src="{{scu.STATIC_DIR}}/js/assiduites.js"></script>
<script>
{% if readonly != "false" %}
function getPeriodValues(){
return [0, 23]
}
{% endif %}
const nonWorkDays = [{{ nonworkdays| safe }}];
const readOnly = {{ readonly }};
setupDate();
updateDate();
if (!readOnly){
setupTimeLine(()=>{
generateAllEtudRow();
});
}
window.forceModule = "{{ forcer_module }}"
window.forceModule = window.forceModule == "True" ? true : false
const etudsDefDem = {{ defdem | safe }}
const select = document.getElementById("moduleimpl_select");
select?.addEventListener('change', (e) => {
generateAllEtudRow();
});
if (window.forceModule) {
const btn = document.getElementById("validate_selectors");
if (!readOnly && select.value == "") {
document.getElementById('forcemodule').style.display = "block";
}
select?.addEventListener('change', (e) => {
if (e.target.value != "") {
document.getElementById('forcemodule').style.display = "none";
} else {
document.getElementById('forcemodule').style.display = "block";
}
});
}
</script>
{% endblock scripts %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.css">
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/assiduites.css">
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/minitimeline.css">
{% endblock styles %}
{% block app_content %}
{% include "assiduites/widgets/toast.j2" %}
{{ minitimeline|safe }}
<section id="content">
<div class="no-display">
@ -78,55 +160,6 @@
{% include "assiduites/widgets/prompt.j2" %}
{% include "assiduites/widgets/conflict.j2" %}
<script>
{% if readonly != "false" %}
function getPeriodValues(){
return [0, 23]
}
{% endif %}
const nonWorkDays = [{{ nonworkdays| safe }}];
const readOnly = {{ readonly }};
setupDate();
updateDate();
if (!readOnly){
setupTimeLine(()=>{
generateAllEtudRow();
});
}
window.forceModule = "{{ forcer_module }}"
window.forceModule = window.forceModule == "True" ? true : false
const etudsDefDem = {{ defdem | safe }}
const select = document.getElementById("moduleimpl_select");
select?.addEventListener('change', (e) => {
generateAllEtudRow();
});
if (window.forceModule) {
const btn = document.getElementById("validate_selectors");
if (!readOnly && select.value == "") {
document.getElementById('forcemodule').style.display = "block";
}
select?.addEventListener('change', (e) => {
if (e.target.value != "") {
document.getElementById('forcemodule').style.display = "none";
} else {
document.getElementById('forcemodule').style.display = "block";
}
});
}
</script>
</section>
{% endblock app_content %}

View File

@ -270,6 +270,10 @@
-webkit-box-sizing: border-box;
border: 10px solid white;
}
.mini-form {
color: black;
}
</style>
<script>

View File

@ -1,3 +1,4 @@
{# Base de toutes les pages ScoDoc #}
{% block doc -%}
<!DOCTYPE html>
<html{% block html_attribs %}{% endblock html_attribs %}>
@ -25,7 +26,10 @@
{% block scripts %}
<script src="{{scu.STATIC_DIR}}/jQuery/jquery.js"></script>
<script src="{{scu.STATIC_DIR}}/libjs/bootstrap/js/bootstrap.js"></script>
<script src="{{scu.STATIC_DIR}}/libjs/bootstrap/js/bootstrap.min.js"></script>
<script>
const SCO_TIMEZONE = "{{ scu.TIME_ZONE }}";
</script>
{%- endblock scripts %}
{%- endblock body %}
</body>

View File

@ -1,4 +1,4 @@
{# -*- mode: jinja-html -*- #}
{# base des pages hors départements (accueil, configuration, ...) #}
{% extends 'babase.j2' %}
{% block styles %}
@ -103,6 +103,5 @@
<script>
const SCO_URL = "{% if g.scodoc_dept %}{{
url_for('scolar.index_html', scodoc_dept=g.scodoc_dept)[:-11] }}{% endif %}";
const SCO_TIMEZONE = "{{ scu.TIME_ZONE }}";
</script>
{% endblock %}

View File

@ -1,4 +1,4 @@
{# -*- mode: jinja-html -*- #}
{# -*- Base des pages ordinaires, dans départements -*- #}
{% extends 'babase.j2' %}
{% block styles %}

View File

@ -85,85 +85,6 @@ from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
# --- UTILS ---
class HTMLElement:
"""Représentation d'un HTMLElement version Python"""
def __init__(self, tag: str, *attr, **kattr) -> None:
self.tag: str = tag
self.children: list["HTMLElement"] = []
self.self_close: bool = kattr.get("self_close", False)
self.text_content: str = kattr.get("text_content", "")
self.key_attributes: dict[str, Any] = kattr
self.attributes: list[str] = list(attr)
def add(self, *child: "HTMLElement") -> None:
"""add child element to self"""
for kid in child:
self.children.append(kid)
def remove(self, child: "HTMLElement") -> None:
"""Remove child element from self"""
if child in self.children:
self.children.remove(child)
def __str__(self) -> str:
attr: list[str] = self.attributes
for att, val in self.key_attributes.items():
if att in ("self_close", "text_content"):
continue
if att != "cls":
attr.append(f'{att}="{val}"')
else:
attr.append(f'class="{val}"')
if not self.self_close:
head: str = f"<{self.tag} {' '.join(attr)}>{self.text_content}"
body: str = "\n".join(map(str, self.children))
foot: str = f"</{self.tag}>"
return head + body + foot
return f"<{self.tag} {' '.join(attr)}/>"
def __add__(self, other: str):
return str(self) + other
def __radd__(self, other: str):
return other + str(self)
class HTMLStringElement(HTMLElement):
"""Utilisation d'une chaine de caracètres pour représenter un element"""
def __init__(self, text: str) -> None:
self.text: str = text
HTMLElement.__init__(self, "textnode")
def __str__(self) -> str:
return self.text
class HTMLBuilder:
def __init__(self, *content: HTMLElement | str) -> None:
self.content: list[HTMLElement | str] = list(content)
def add(self, *element: HTMLElement | str):
self.content.extend(element)
def remove(self, element: HTMLElement | str):
if element in self.content:
self.content.remove(element)
def __str__(self) -> str:
return "\n".join(map(str, self.content))
def build(self) -> str:
return self.__str__()
# --------------------------------------------------------------------
#
# Assiduité (/ScoDoc/<dept>/Scolarite/Assiduites/...)
@ -539,18 +460,6 @@ def liste_assiduites_etud():
assiduite_id: int = request.args.get("assiduite_id", -1)
# Préparation de la page
header: str = html_sco_header.sco_header(
page_title=f"Assiduité de {etud.nomprenom}",
init_qtip=True,
javascripts=[
"js/assiduites.js",
"js/date_utils.js",
],
cssstyles=CSSSTYLES
+ [
"css/assiduites.css",
],
)
tableau = _prepare_tableau(
liste_assi.AssiJustifData.from_etudiants(
etud,
@ -563,16 +472,14 @@ def liste_assiduites_etud():
)
if not tableau[0]:
return tableau[1]
# Peuplement du template jinja
return HTMLBuilder(
header,
render_template(
# Page HTML:
return render_template(
"assiduites/pages/liste_assiduites.j2",
sco=ScoData(etud),
assi_id=assiduite_id,
etud=etud,
tableau=tableau[1],
),
).build()
sco=ScoData(etud),
)
@bp.route("/bilan_etud")
@ -593,20 +500,6 @@ def bilan_etud():
if etud.dept_id != g.scodoc_dept_id:
abort(404, "étudiant inexistant dans ce département")
# Préparation de la page (header)
header: str = html_sco_header.sco_header(
page_title=f"Bilan de l'assiduité de {etud.nomprenom}",
init_qtip=True,
javascripts=[
"js/assiduites.js",
"js/date_utils.js",
],
cssstyles=CSSSTYLES
+ [
"css/assiduites.css",
],
)
# Gestion des dates du bilan (par défaut l'année scolaire)
date_debut = scu.date_debut_annee_scolaire().strftime("%d/%m/%Y")
date_fin: str = scu.date_fin_annee_scolaire().strftime("%d/%m/%Y")
@ -639,23 +532,20 @@ def bilan_etud():
if not table[0]:
return table[1]
# Génération de la page
return HTMLBuilder(
header,
render_template(
# Génération de la page HTML
return render_template(
"assiduites/pages/bilan_etud.j2",
sco=ScoData(etud),
date_debut=date_debut,
date_fin=date_fin,
assi_metric=assi_metric,
assi_seuil=_get_seuil(),
assi_limit_annee=sco_preferences.get_preference(
"assi_limit_annee",
dept_id=g.scodoc_dept_id,
),
assi_metric=assi_metric,
assi_seuil=_get_seuil(),
date_debut=date_debut,
date_fin=date_fin,
sco=ScoData(etud),
tableau=table[1],
),
).build()
)
@bp.route("/edit_justificatif_etud/<int:justif_id>", methods=["GET", "POST"])
@ -1105,55 +995,33 @@ def signal_assiduites_group():
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
)
# --- Génération de l'HTML ---
header: str = html_sco_header.sco_header(
page_title="Saisie journalière des assiduités",
init_qtip=True,
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
+ [
# Voir fonctionnement JS
"js/etud_info.js",
"js/groups_view.js",
"js/assiduites.js",
"js/date_utils.js",
],
cssstyles=CSSSTYLES
+ [
"css/assiduites.css",
"css/minitimeline.css",
],
)
# Récupération du semestre en dictionnaire
sem = formsemestre.to_dict()
# Peuplement du template jinja
return HTMLBuilder(
header,
_mini_timeline(),
render_template(
# Page HTML
return render_template(
"assiduites/pages/signal_assiduites_group.j2",
gr_tit=gr_tit,
sem=sem["titre_num"],
date=_dateiso_to_datefr(date),
formsemestre_id=formsemestre_id,
grp=sco_groups_view.menu_groups_choice(groups_infos),
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
timeline=_timeline(heures=",".join([f"'{s}'" for s in heures])),
nonworkdays=_non_work_days(),
formsemestre_date_debut=str(formsemestre.date_debut),
formsemestre_date_fin=str(formsemestre.date_fin),
defdem=_get_etuds_dem_def(formsemestre),
forcer_module=sco_preferences.get_preference(
"forcer_module",
formsemestre_id=formsemestre_id,
dept_id=g.scodoc_dept_id,
),
defdem=_get_etuds_dem_def(formsemestre),
formsemestre_date_debut=str(formsemestre.date_debut),
formsemestre_date_fin=str(formsemestre.date_fin),
formsemestre_id=formsemestre_id,
gr_tit=gr_tit,
grp=sco_groups_view.menu_groups_choice(groups_infos),
minitimeline=_mini_timeline(),
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
nonworkdays=_non_work_days(),
readonly="false",
),
html_sco_header.sco_footer(),
).build()
sco=ScoData(formsemestre=formsemestre),
sem=sem["titre_num"],
timeline=_timeline(heures=",".join([f"'{s}'" for s in heures])),
title="Saisie journalière des assiduités",
)
@bp.route("/visu_assiduites_group")
@ -1248,7 +1116,7 @@ def visu_assiduites_group():
# Si aucun etudiant n'est inscrit au module choisi...
moduleimpl_id = None
# --- Génération de l'HTML ---
# --- Génération du HTML ---
if groups_infos.tous_les_etuds_du_sem:
gr_tit = "en"
@ -1261,52 +1129,32 @@ def visu_assiduites_group():
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
)
header: str = html_sco_header.sco_header(
page_title="Saisie journalière de l'assiduité",
init_qtip=True,
javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
+ [
# Voir fonctionnement JS
"js/etud_info.js",
"js/groups_view.js",
"js/assiduites.js",
"js/date_utils.js",
],
cssstyles=CSSSTYLES
+ [
"css/assiduites.css",
"css/minitimeline.css",
],
)
# Récupération du semestre en dictionnaire
sem = formsemestre.to_dict()
return HTMLBuilder(
header,
_mini_timeline(),
render_template(
return render_template(
"assiduites/pages/signal_assiduites_group.j2",
gr_tit=gr_tit,
sem=sem["titre_num"],
date=_dateiso_to_datefr(date),
formsemestre_id=formsemestre_id,
grp=sco_groups_view.menu_groups_choice(groups_infos),
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
timeline=_timeline(),
nonworkdays=_non_work_days(),
formsemestre_date_debut=str(formsemestre.date_debut),
formsemestre_date_fin=str(formsemestre.date_fin),
defdem=_get_etuds_dem_def(formsemestre),
forcer_module=sco_preferences.get_preference(
"forcer_module",
formsemestre_id=formsemestre_id,
dept_id=g.scodoc_dept_id,
),
defdem=_get_etuds_dem_def(formsemestre),
formsemestre_date_debut=str(formsemestre.date_debut),
formsemestre_date_fin=str(formsemestre.date_fin),
formsemestre_id=formsemestre_id,
gr_tit=gr_tit,
grp=sco_groups_view.menu_groups_choice(groups_infos),
minitimeline=_mini_timeline(),
moduleimpl_select=_module_selector(formsemestre, moduleimpl_id),
nonworkdays=_non_work_days(),
sem=sem["titre_num"],
timeline=_timeline(),
readonly="true",
),
html_sco_header.sco_footer(),
).build()
sco=ScoData(formsemestre=formsemestre),
title="Saisie journalière de l'assiduité",
)
class RowEtudWithAssi(RowEtud):
@ -1828,7 +1676,9 @@ def _preparer_objet(
@scodoc
@permission_required(Permission.AbsChange)
def signal_assiduites_diff():
"""TODO documenter"""
"""TODO documenter
Utilisé notamment par "Saisie différée" sur tableau de bord semetstre"
"""
# Récupération des paramètres de la requête
group_ids: list[int] = request.args.get("group_ids", None)
formsemestre_id: int = request.args.get("formsemestre_id", -1)
@ -1910,10 +1760,10 @@ def signal_assiduites_diff():
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
)
return HTMLBuilder(
header,
render_template(
return render_template(
"assiduites/pages/signal_assiduites_diff.j2",
defaultDates=_get_days_between_dates(date_deb, date_fin),
defdem=_get_etuds_dem_def(formsemestre),
diff=_differee(
etudiants=etudiants,
moduleimpl_select=_module_selector(
@ -1926,16 +1776,13 @@ def signal_assiduites_diff():
},
),
gr=gr_tit,
nonworkdays=_non_work_days(),
sco=ScoData(formsemestre=formsemestre),
sem=formsemestre.titre_num(),
defdem=_get_etuds_dem_def(formsemestre),
timeEvening=ScoDocSiteConfig.get("assi_afternoon_time", "18:00:00"),
timeMorning=ScoDocSiteConfig.get("assi_morning_time", "08:00:00"),
timeNoon=ScoDocSiteConfig.get("assi_lunch_time", "13:00:00"),
timeEvening=ScoDocSiteConfig.get("assi_afternoon_time", "18:00:00"),
defaultDates=_get_days_between_dates(date_deb, date_fin),
nonworkdays=_non_work_days(),
),
html_sco_header.sco_footer(),
).build()
)
@bp.route("/signale_evaluation_abs/<int:evaluation_id>/<int:etudid>")