Files
PlanarianScanner/test_tube_scanner/planarian/templates/planarian/experiment_form.html
T
2026-05-04 19:05:40 +02:00

546 lines
27 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "planarian/base.html" %}
{% load i18n %}
{% block content %}
<div class="w3-container w3-padding-small" style="max-width:960px; margin:auto;">
<!-- En-tête de la page -->
<div class="w3-panel w3-teal w3-round-large w3-padding-16" style="margin-bottom:2rem;">
<div class="w3-row w3-bar-item">
<span class="w3-xlarge">
<i class="w3-margin-right">🔬</i>
{% if object %}
{% trans "Modifier la configuration" %} — {{ object }}
{% else %}
{% trans "Nouvelle configuration d'expérience" %}
{% endif %}
</span>
</div>
</div>
<!-- Messages Django -->
{% for message in messages %}
<div class="w3-panel w3-round
{% if message.tags == 'success' %}w3-green
{% elif message.tags == 'error' %}w3-red
{% elif message.tags == 'warning' %}w3-orange
{% else %}w3-blue{% endif %}">
<p>{{ message }}</p>
</div>
{% endfor %}
<form method="post" novalidate>
{% csrf_token %}
<!-- Erreurs globales du formulaire -->
{% if form.non_field_errors %}
<div class="w3-panel w3-red w3-round">
{% for error in form.non_field_errors %}
<p>⚠ {{ error }}</p>
{% endfor %}
</div>
{% endif %}
<!-- ============================================================
Section 1 : Identification
============================================================ -->
<div class="w3-card-4 w3-round-large w3-margin-bottom w3-border w3-round w3-round-large">
<header class="w3-container w3-teal w3-round w3-round-large">
<h3 class="w3-text-white">{% trans "Identification" %}</h3>
</header>
<div class="w3-container w3-padding">
<div class="w3-row w3-row-padding">
<!-- identifier -->
<div class="w3-half">
<label class="w3-text-teal"><b>{{ form.identifier.label }}</b></label>
{{ form.identifier }}
{% if form.identifier.errors %}
<span class="w3-text-red w3-small">{{ form.identifier.errors|join:", " }}</span>
{% endif %}
</div>
<!-- author -->
<div class="w3-half w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.author.label }}</b></label>
{{ form.author }}
{% if form.author.errors %}
<span class="w3-text-red w3-small">{{ form.author.errors|join:", " }}</span>
{% endif %}
</div>
<!-- Experiment -->
<div class="w3-half w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.experiment.label }}</b></label>
{{ form.experiment }}
{% if form.experiment.errors %}
<span class="w3-text-red w3-small">{{ form.experiment.errors|join:", " }}</span>
{% endif %}
</div>
<!-- Well -->
<div class="w3-half w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.well.label }}</b></label>
{{ form.well }}
{% if form.well.errors %}
<span class="w3-text-red w3-small">{{ form.well.errors|join:", " }}</span>
{% endif %}
</div>
</div>
<!-- Description -->
<div class="w3-margin-bottom w3-padding">
<label class="w3-text-teal"><b>{{ form.description.label }}</b></label>
{{ form.description }}
{% if form.description.errors %}
<span class="w3-text-red w3-small">{{ form.description.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
<!-- ============================================================
Section 2 : Calibration optique
============================================================ -->
<div class="w3-card-4 w3-round-large w3-margin-bottom w3-border w3-round w3-round-large">
<header class="w3-container w3-blue-grey w3-round w3-round-top-large">
<h3 class="w3-text-white">{% trans "Calibration optique" %}</h3>
</header>
<div class="w3-container w3-padding-24">
<div class="w3-row w3-row-padding">
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-blue-grey"><b>{{ form.px_per_mm.label }}</b></label>
{% if form.px_per_mm.help_text %}
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{{ form.px_per_mm.help_text }}</p>
{% endif %}
{{ form.px_per_mm }}
{% if form.px_per_mm.errors %}
<span class="w3-text-red w3-small">{{ form.px_per_mm.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-blue-grey"><b>{{ form.fps.label }}</b></label>
{% if form.fps.help_text %}
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{{ form.fps.help_text }}</p>
{% endif %}
{{ form.fps }}
{% if form.fps.errors %}
<span class="w3-text-red w3-small">{{ form.fps.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-blue-grey"><b>{{ form.well_radius_mm.label }}</b></label>
{% if form.well_radius_mm.help_text %}
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{{ form.well_radius_mm.help_text }}</p>
{% endif %}
{{ form.well_radius_mm }}
{% if form.well_radius_mm.errors %}
<span class="w3-text-red w3-small">{{ form.well_radius_mm.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- ============================================================
Section 4 : Tracker
============================================================ -->
<div class="w3-card-4 w3-round-large w3-margin-bottom w3-border w3-round w3-round-large">
<header class="w3-container w3-dark-grey w3-round w3-round-top-large">
<h3 class="w3-text-white">{% trans "Tracker" %}</h3>
</header>
<div class="w3-container w3-padding-24">
<div class="w3-row-padding">
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-grey"><b>{{ form.tube_axis.label }}</b></label>
{{ form.tube_axis }}
{% if form.tube_axis.errors %}
<span class="w3-text-red w3-small">{{ form.tube_axis.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-grey"><b>{{ form.min_area_px.label }}</b></label>
{{ form.min_area_px }}
{% if form.min_area_px.errors %}
<span class="w3-text-red w3-small">{{ form.min_area_px.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-grey"><b>{{ form.max_area_ratio.label }}</b></label>
{{ form.max_area_ratio }}
{% if form.max_area_ratio.errors %}
<span class="w3-text-red w3-small">{{ form.max_area_ratio.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-grey"><b>{{ form.planarian_count.label }}</b></label>
{{ form.planarian_count }}
{% if form.planarian_count.errors %}
<span class="w3-text-red w3-small">{{ form.planarian_count.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-grey"><b>{{ form.min_contour_dist_px.label }}</b></label>
{{ form.min_contour_dist_px }}
{% if form.min_contour_dist_px.errors %}
<span class="w3-text-red w3-small">{{ form.min_contour_dist_px.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-grey"><b>{{ form.merge_kernel_size.label }}</b></label>
{{ form.merge_kernel_size }}
{% if form.merge_kernel_size.errors %}
<span class="w3-text-red w3-small">{{ form.merge_kernel_size.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- ============================================================
Section 3 : Seuils de mobilité EthoVision
============================================================ -->
<div class="w3-card-4 w3-round-large w3-margin-bottom w3-border w3-round w3-round-large">
<header class="w3-container w3-indigo w3-round w3-round-top-large">
<h3 class="w3-text-white">{% trans "Seuils de mobilité EthoVision XT" %}</h3>
</header>
<div class="w3-container w3-padding-24">
<!-- Visualisation des seuils -->
<div class="w3-light-grey w3-round w3-margin-bottom" style="height:32px; position:relative; overflow:hidden;">
<div style="position:absolute; left:0; width:13%; height:100%; background:#c0392b; display:flex; align-items:center; justify-content:center;">
<span class="w3-small w3-text-white"><b>{% trans "Immobile" %}</b></span>
</div>
<div style="position:absolute; left:13%; width:27%; height:100%; background:#e67e22; display:flex; align-items:center; justify-content:center;">
<span class="w3-small w3-text-white"><b>{% trans "Mobile" %}</b></span>
</div>
<div style="position:absolute; left:40%; right:0; height:100%; background:#27ae60; display:flex; align-items:center; justify-content:center;">
<span class="w3-small w3-text-white"><b>{% trans "Très mobile" %}</b></span>
</div>
</div>
<p class="w3-small w3-text-grey" style="margin-top:-8px; margin-bottom:16px;">
{% trans "Représentation indicative des zones de mobilité (défauts EthoVision : 0.2 / 1.5 mm/s)" %}
</p>
<div class="w3-row-padding">
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-indigo"><b>{{ form.thresh_immobile.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "En-dessous : Immobile (mm/s)" %}</p>
{{ form.thresh_immobile }}
{% if form.thresh_immobile.errors %}
<span class="w3-text-red w3-small">{{ form.thresh_immobile.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-indigo"><b>{{ form.thresh_mobile.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "En-dessous : Mobile, au-delà : Très mobile (mm/s)" %}</p>
{{ form.thresh_mobile }}
{% if form.thresh_mobile.errors %}
<span class="w3-text-red w3-small">{{ form.thresh_mobile.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- ============================================================
Section 5 : Comportements (accordéon W3.CSS)
============================================================ -->
<div class="w3-card-4 w3-round-large w3-margin-bottom w3-border w3-round w3-round-large">
<header class="w3-container w3-teal w3-round w3-round-top-large">
<h3 class="w3-text-white">{% trans "Comportements" %}</h3>
</header>
<!-- --- Thigmotactisme --- -->
<div class="w3-container w3-padding-16 w3-border-bottom">
<button type="button" class="w3-button w3-block w3-left-align w3-hover-light-grey"
onclick="toggleSection('thigmo')">
<span class="w3-large">🫧</span>
<b class="w3-margin-left">{% trans "Thigmotactisme" %}</b>
<span class="w3-small w3-text-grey w3-margin-left">
{% trans "Attraction vers la paroi du puits" %}
</span>
<span id="thigmo-icon" class="w3-right"></span>
</button>
<div id="thigmo" class="w3-padding-top">
<div class="w3-row-padding">
<div class="w3-col m6 s12">
<label class="w3-text-teal"><b>{{ form.thigmotaxis_wall_dist_mm.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">
{% trans "Distance à la paroi considérée « près du bord » (mm)" %}
</p>
{{ form.thigmotaxis_wall_dist_mm }}
{% if form.thigmotaxis_wall_dist_mm.errors %}
<span class="w3-text-red w3-small">{{ form.thigmotaxis_wall_dist_mm.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- --- Phototactisme --- -->
<div class="w3-container w3-padding-16 w3-border-bottom">
<button type="button" class="w3-button w3-block w3-left-align w3-hover-light-grey" onclick="toggleSection('photo')">
<span class="w3-large">💡</span>
<b class="w3-margin-left">{% trans "Phototactisme" %}</b>
<span class="w3-small w3-text-grey w3-margin-left">
{% trans "Fuite de la lumière" %}
</span>
<span id="photo-icon" class="w3-right"></span>
</button>
<div id="photo" class="w3-hide w3-padding-top">
<div class="w3-row-padding">
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.photo_mode.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">&nbsp;</p>
{{ form.photo_mode }}
{% if form.photo_mode.errors %}
<span class="w3-text-red w3-small">{{ form.photo_mode.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.photo_strength.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "0.0 = désactivé → 1.0 = fort" %}</p>
{{ form.photo_strength }}
{% if form.photo_strength.errors %}
<span class="w3-text-red w3-small">{{ form.photo_strength.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.photo_x.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">&nbsp;</p>
{{ form.photo_x }}
{% if form.photo_x.errors %}
<span class="w3-text-red w3-small">{{ form.photo_x.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.photo_y.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">&nbsp;</p>
{{ form.photo_y }}
{% if form.photo_y.errors %}
<span class="w3-text-red w3-small">{{ form.photo_y.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- --- Chimiotactisme --- -->
<div class="w3-container w3-padding-16 w3-border-bottom">
<button type="button" class="w3-button w3-block w3-left-align w3-hover-light-grey"
onclick="toggleSection('chemo')">
<span class="w3-large">🍖</span>
<b class="w3-margin-left">{% trans "Chimiotactisme" %}</b>
<span class="w3-small w3-text-grey w3-margin-left">
{% trans "Attraction vers une source de nourriture" %}
</span>
<span id="chemo-icon" class="w3-right"></span>
</button>
<div id="chemo" class="w3-hide w3-padding-top">
<div class="w3-row-padding">
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.chemo_strength.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "0.0 = désactivé → 1.0 = fort" %}</p>
{{ form.chemo_strength }}
{% if form.chemo_strength.errors %}
<span class="w3-text-red w3-small">{{ form.chemo_strength.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.chemo_x.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "Mini = 0, maxi = 1" %}</p>
{{ form.chemo_x }}
{% if form.chemo_x.errors %}
<span class="w3-text-red w3-small">{{ form.chemo_x.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m4 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.chemo_y.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "Mini = 0, maxi = 1" %}</p>
{{ form.chemo_y }}
{% if form.chemo_y.errors %}
<span class="w3-text-red w3-small">{{ form.chemo_y.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.chemo_radius_mm.label }}</b></label>
{{ form.chemo_radius_mm }}
{% if form.chemo_radius_mm.errors %}
<span class="w3-text-red w3-small">{{ form.chemo_radius_mm.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- --- Interactions inter-individus --- -->
<div class="w3-container w3-padding-16">
<button type="button" class="w3-button w3-block w3-left-align w3-hover-light-grey"
onclick="toggleSection('social')">
<span class="w3-large">🔀</span>
<b class="w3-margin-left">{% trans "Interactions inter-individus" %}</b>
<span class="w3-small w3-text-grey w3-margin-left">
{% trans "Évitement et agrégation" %}
</span>
<span id="social-icon" class="w3-right"></span>
</button>
<div id="social" class="w3-hide w3-padding-top">
<div class="w3-row-padding">
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.avoid_radius_mm.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "Rayon de répulsion courte portée (mm)" %}</p>
{{ form.avoid_radius_mm }}
{% if form.avoid_radius_mm.errors %}
<span class="w3-text-red w3-small">{{ form.avoid_radius_mm.errors|join:", " }}</span>
{% endif %}
</div>
<div class="w3-col m6 s12 w3-margin-bottom">
<label class="w3-text-teal"><b>{{ form.aggreg_radius_mm.label }}</b></label>
<p class="w3-small w3-text-grey" style="margin:0 0 4px;">{% trans "Rayon d'attraction longue portée — doit être > rayon évitement (mm)" %}</p>
{{ form.aggreg_radius_mm }}
{% if form.aggreg_radius_mm.errors %}
<span class="w3-text-red w3-small">{{ form.aggreg_radius_mm.errors|join:", " }}</span>
{% endif %}
</div>
</div>
</div>
</div>
</div><!-- fin card comportements -->
<!-- ============================================================
Boutons d'action
============================================================ -->
<div class="w3-row-padding w3-margin-top">
<div class="w3-col m8 s12 w3-margin-bottom">
<button type="submit" class="w3-button w3-teal w3-round w3-large w3-padding-large">
{% if is_update %}
💾 {% trans "Enregistrer les modifications" %}
{% else %}
{% trans "Créer la configuration" %}
{% endif %}
</button>
<a href="{% url 'planarian:experiment-list' %}"
class="w3-button w3-light-grey w3-round w3-large w3-padding-large w3-margin-left">
✖ {% trans "Retour" %}
</a>
</div>
{% if object %}
<div class="w3-col m4 s12 w3-right-align w3-margin-bottom">
<a href="{% url 'planarian:export-csv' %}?experiment={{ object.experiment }}&well={{ object.well }}"
class="w3-button w3-blue w3-round w3-large w3-padding-large">
📥 {% trans "Exporter CSV" %}
</a>
</div>
{% endif %}
</div>
</form><!-- fin form -->
</div><!-- fin container -->
<!-- ============================================================
Styles W3.CSS pour les champs de formulaire Django
(Django génère des <input> bruts sans classes — on les stylise ici)
============================================================ -->
<style>
/* Champs texte, number, select */
input[type="text"],
input[type="number"],
input[type="email"],
textarea,
select {
width: 100%;
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 15px;
box-sizing: border-box;
margin-top: 2px;
background-color: #fafafa;
transition: border-color 0.2s;
}
input[type="text"]:focus,
input[type="number"]:focus,
textarea:focus,
select:focus {
border-color: #009688; /* teal W3.CSS */
outline: none;
background-color: #fff;
}
/* Champ en erreur */
input.errorfield, select.errorfield, textarea.errorfield {
border-color: #f44336;
background-color: #fff8f8;
}
/* Label au-dessus du champ */
label {
display: block;
margin-bottom: 2px;
font-size: 14px;
}
/* Sections accordéon */
[id$="-icon"] {
transition: transform 0.2s;
}
</style>
<script>
/**
* Bascule la visibilité d'une section accordéon.
* @param {string} id - Identifiant de la section (sans le préfixe)
*/
function toggleSection(id) {
const section = document.getElementById(id);
const icon = document.getElementById(id + '-icon');
if (section.classList.contains('w3-hide')) {
section.classList.remove('w3-hide');
if (icon) icon.textContent = '▲';
} else {
section.classList.add('w3-hide');
if (icon) icon.textContent = '▼';
}
}
/* Ouvrir automatiquement les sections qui contiennent des erreurs */
document.addEventListener('DOMContentLoaded', function () {
['thigmo', 'photo', 'chemo', 'social'].forEach(function (id) {
const section = document.getElementById(id);
if (section && section.querySelector('.w3-text-red')) {
section.classList.remove('w3-hide');
const icon = document.getElementById(id + '-icon');
if (icon) icon.textContent = '▲';
}
});
});
</script>
{% endblock %}