loko/streetup/interventions/templates/interventions/interventions_index.html

1210 lines
68 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 "base.html" %}
{% load static %}
{% load i18n %}
{% block head %}
<!-- Mapbox GL Draw 1.5.0 (local) -->
<link href="{% static 'common/mapbox-gl-draw.css' %}" rel="stylesheet"/>
<!-- <style>
.mapbox-gl-draw_ctrl-group .mapbox-gl-draw_ctrl-draw-btn {
background-repeat: no-repeat;
background-position: center;
}
.mapbox-gl-draw_polygon:before {
content: '';
width: 18px; height:18px;
background-image: url('data:image/svg+xml;utf8,<svg fill="%23007cbf" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L2 7l10 5 10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>');
}
.mapbox-gl-draw_rectangle:before {
content: '';
width: 18px; height:18px;
background-image: url('data:image/svg+xml;utf8,<svg fill="%23faa" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="6" width="18" height="12" rx="2"/></svg>');
}
.mapbox-gl-draw_circle:before {
content: '';
width: 18px; height:18px;
background-image: url('data:image/svg+xml;utf8,<svg fill="%23afa" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="8"/></svg>');
}
</style> -->
<style>
i.small-icon {
font-size: 0.8rem;
}
#interventions-table-container {
position: relative;
}
#filter-dropdown-wrapper {
position: absolute;
top: 0.5rem;
left: 0.5rem;
z-index: 10;
margin-top: 2px;
}
.popup-scrollable {
max-height: 200px;
overflow-y: auto;
}
/* jQuery UI autocomplete above Bootstrap modal */
.ui-autocomplete {
z-index: 1060 !important;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
}
/* Supprime le contour bleu Bootstrap au focus sur l'input de recherche */
#interventions-search-input:focus {
outline: none;
box-shadow: none;
border-color: #dee2e6;
}
/* multi-select compacte et scrollable */
.form-select[multiple].bs-iconized {
min-height: 3.25rem;
max-height: 10rem;
overflow-y: auto;
}
/* tenter d’enlever le fond du système pour l’état sélectionné */
.form-select[multiple].bs-iconized option:checked {
background-color: #e1f6ff !important;
color: inherit;
}
/* focus clair */
.form-select[multiple].bs-iconized:focus {
border-color: var(--bs-primary);
box-shadow: 0 0 0 .2rem rgba(13,110,253,.25);
}
/* petite ligne de synthèse (facultative) */
.bs-summary {
margin-top: .35rem;
color: var(--bs-secondary-color);
font-size: .875rem;
}
.location-item {
background-color: #e1f6ff;
}
/* Styles pour la modale de filtre */
#filterModal .modal-dialog {
max-width: 95%;
}
#filterModal .modal-content {
display: flex;
flex-direction: column;
max-height: 90vh;
}
#filterModal .modal-body {
flex: 1;
overflow-y: auto;
}
#filterModal .modal-footer {
flex-shrink: 0;
}
.filter-section {
margin-bottom: 1rem;
}
/* Default badge styling */
.filter-option label {
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
font-weight: 500;
cursor: pointer;
background-color: #e7f1ff;
color: #0c5cc9;
border-radius: 1rem;
padding: 0.4rem 0.5rem;
font-size: 0.75rem;
border: 1px solid #b8d4f1;
transition: all 0.2s ease;
width: 140px;
flex: 1 1 auto;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Contextual color badges - inactive state (outline) */
.filter-option label.context-badge {
border-color: currentColor;
color: inherit;
background-color: transparent;
}
/* Bootstrap outline color mappings */
.filter-option label.btn-outline-primary {
border-color: #0c5cc9;
color: #0c5cc9;
}
.filter-option label.btn-outline-danger {
border-color: #dc3545;
color: #dc3545;
}
.filter-option label.btn-outline-warning {
border-color: #ffc107;
color: #ffc107;
}
.filter-option label.btn-outline-success {
border-color: #28a745;
color: #28a745;
}
.filter-option label.btn-outline-info {
border-color: #17a2b8;
color: #17a2b8;
}
.filter-option label.btn-outline-dark {
border-color: #343a40;
color: #343a40;
}
.filter-option label.btn-outline-secondary {
border-color: #6c757d;
color: #6c757d;
}
/* Default badges - checked state */
.filter-option input[type="checkbox"]:checked + label:not(.context-badge) {
background-color: #0c5cc9;
color: white;
border-color: #0c5cc9;
}
/* Contextual badges - checked state (filled/enfoncé) */
.filter-option input[type="checkbox"]:checked + label.context-badge {
color: white;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-primary {
background-color: #0c5cc9;
border-color: #0c5cc9;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-danger {
background-color: #dc3545;
border-color: #dc3545;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-warning {
background-color: #ffc107;
border-color: #ffc107;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-success {
background-color: #28a745;
border-color: #28a745;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-info {
background-color: #17a2b8;
border-color: #17a2b8;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-dark {
background-color: #343a40;
border-color: #343a40;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-secondary {
background-color: #6c757d;
border-color: #6c757d;
}
/* Default badges - hover */
.filter-option input[type="checkbox"]:hover + label:not(.context-badge) {
background-color: #cfe2f3;
}
/* Contextual badges - hover */
.filter-option input[type="checkbox"]:hover + label.context-badge {
background-color: inherit;
}
.filter-section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
gap: 1rem;
}
.filter-section-header label {
font-weight: 600;
color: #333;
margin: 0;
flex-shrink: 0;
}
.filter-section-buttons {
display: flex;
gap: 0.5rem;
margin-left: auto;
flex-shrink: 0;
}
.filter-section-buttons button {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
white-space: nowrap;
}
.filter-options {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
min-height: 2.5rem;
padding: 0.5rem;
background-color: #f8f9fa;
border-radius: 0.375rem;
border: 1px solid #dee2e6;
}
.filter-option {
display: flex;
align-items: center;
gap: 0.5rem;
}
.filter-option.subcategory-option {
font-size: 0.875em;
color: #555;
}
.filter-option-break {
flex-basis: 100%;
height: 0;
}
.filter-subcat-controls {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.filter-option input[type="checkbox"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
cursor: pointer;
}
/* Réduire la taille de police pour tout le tableau des interventions */
#interventions-table {
font-size: 0.85rem;
}
/* Style pour la colonne titre - limité à 2 lignes avec ellipsis */
.intervention-title-cell {
font-size: 0.85rem;
max-height: 2.8em;
line-height: 1.4;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-wrap: break-word;
}
/* Tooltip only on truncated text */
.intervention-title-cell[data-truncated="true"] {
cursor: help;
}
/* Harmoniser la taille de police du header du tableau */
#interventions-table thead th,
#interventions-table thead .th-inner,
.fixed-table-header,
.fixed-table-header .th-inner {
font-size: 0.85rem;
}
/* Styled restore button when in expanded mode */
.restore-btn-styled {
border-radius: 10px !important;
border: 1px solid rgba(0, 0, 0, 0.15) !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12) !important;
transition: all 0.2s ease !important;
}
.restore-btn-styled:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18) !important;
transform: translateY(-1px);
}
.restore-btn-styled i {
font-size: 1.1rem;
}
/* Priority gradients & custom styles */
.filter-option label.btn-outline-priority-1 {
border-color: #dc3545;
color: #dc3545;
}
.filter-option label.btn-outline-priority-2 {
border-color: #fd7e14;
color: #fd7e14;
}
.filter-option label.btn-outline-priority-3 {
border-color: #0d6efd;
color: #0d6efd;
}
.filter-option label.btn-outline-priority-4 {
border-color: #6c757d;
color: #6c757d;
}
.filter-option label[class*="btn-outline-priority-"] {
transition: all 0.2s ease-in-out;
}
.filter-option input[type="checkbox"]:hover + label[class*="btn-outline-priority-"] {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.08);
}
.filter-option input[type="checkbox"]:hover + label.btn-outline-priority-1:not(:checked) {
background-color: rgba(220, 53, 69, 0.05);
}
.filter-option input[type="checkbox"]:hover + label.btn-outline-priority-2:not(:checked) {
background-color: rgba(253, 126, 20, 0.05);
}
.filter-option input[type="checkbox"]:hover + label.btn-outline-priority-3:not(:checked) {
background-color: rgba(13, 110, 253, 0.05);
}
.filter-option input[type="checkbox"]:hover + label.btn-outline-priority-4:not(:checked) {
background-color: rgba(108, 117, 125, 0.05);
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-priority-1 {
background: linear-gradient(135deg, #dc3545 0%, #ff5e62 100%) !important;
border-color: #dc3545 !important;
color: white !important;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-priority-2 {
background: linear-gradient(135deg, #fd7e14 0%, #ffb703 100%) !important;
border-color: #fd7e14 !important;
color: white !important;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-priority-3 {
background: linear-gradient(135deg, #0d6efd 0%, #00b4d8 100%) !important;
border-color: #0d6efd !important;
color: white !important;
}
.filter-option input[type="checkbox"]:checked + label.btn-outline-priority-4 {
background: linear-gradient(135deg, #6c757d 0%, #adb5bd 100%) !important;
border-color: #6c757d !important;
color: white !important;
}
</style>
{% endblock head %}
{% block content %}
<!-- Modal for choosing intervention type -->
<div class="modal fade" id="interventionTypeModal" tabindex="-1" aria-labelledby="interventionTypeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="interventionTypeModalLabel">{% translate "Choisir le type d’intervention" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body d-flex flex-column gap-2">
<a href="{% url 'interventions:intervention_add_choose_thematic' %}?type=corrective" class="btn btn-outline-danger w-100">
<i class="bi bi-gear"></i> {% translate "Intervention corrective" %}<br>
<small class="text-muted">{% translate "Réparer ou corriger un dysfonctionnement (avarie, panne, défaut, ...)" %}</small>
</a>
{% if can_create_preventive %}
<a href="{% url 'interventions:intervention_add_choose_thematic' %}?type=preventive" class="btn btn-outline-warning w-100">
<i class="bi bi-gear"></i> {% translate "Interventions préventives" %}<br>
<small class="text-muted">{% translate "Anticiper un problème potentiel (entretien cyclique, ...)" %} </small>
</a>
{% endif %}
{% if can_create_ameliorative %}
<a href="{% url 'interventions:intervention_add_choose_thematic' %}?type=ameliorative" class="btn btn-outline-success w-100">
<i class="bi bi-gear"></i> {% translate "Intervention améliorative" %}<br>
<small class="text-muted">{% translate "Optimiser ou améliorer une situation existante (projet, fonctionnel, ...)" %}</small>
</a>
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
</div>
</div>
</div>
</div>
<!-- Modale pour le filtre des interventions -->
<div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les interventions" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body">
<!-- Formulaire de filtre -->
<form method="get" id="filter-form" class="mb-4">
<!-- Thématique, Statut et Catégorie -->
<div class="row">
<!-- Thématique -->
<div class="col-12 filter-section">
<div class="filter-section-header">
<label>{% translate "Thématique" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="thematic">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="thematic">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="thematic">
{% for key, value, icon in thematic_choices %}
<div class="filter-option">
<input type="checkbox" name="thematic" id="thematic_{{ key }}" value="{{ key }}" {% if key in selected_thematics %}checked{% endif %}>
<label for="thematic_{{ key }}">
{% if icon %}<i class="bi {{ icon }} me-2"></i>{% endif %}{{ value }}
</label>
</div>
{% endfor %}
</div>
</div>
<!-- Statut -->
<div class="col-12 filter-section">
<div class="filter-section-header">
<label>{% translate "Statut" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="status">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="status">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="status">
{% for key, value, css_class in status_choices %}
<div class="filter-option">
<input type="checkbox" name="status" id="status_{{ key }}" value="{{ key }}" {% if key in selected_statuses %}checked{% endif %}>
<label for="status_{{ key }}" class="context-badge status-{{ key }} btn-outline-{{ css_class }}">{{ value }}</label>
</div>
{% endfor %}
</div>
</div>
<!-- Raisons de mise en pause -->
<div class="col-md-6 filter-section {% if not pause_reason_filter_enabled %}d-none{% endif %}" id="pause-reason-filter">
<div class="filter-section-header">
<label>{% translate "Raisons de la mise en pause" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="pause_reason" {% if not pause_reason_filter_enabled %}disabled{% endif %}>{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="pause_reason" {% if not pause_reason_filter_enabled %}disabled{% endif %}>{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="pause_reason">
{% for key, value in pause_reason_choices %}
<div class="filter-option">
<input type="checkbox" name="pause_reason" id="pause_reason_{{ key }}" value="{{ key }}" {% if key in selected_pause_reasons %}checked{% endif %} {% if not pause_reason_filter_enabled %}disabled{% endif %}>
<label for="pause_reason_{{ key }}">{{ value }}</label>
</div>
{% endfor %}
</div>
</div>
<!-- Catégorie d'intervention (full width) -->
<div class="col-12 filter-section">
<div class="filter-section-header">
<label>{% translate "Catégorie" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="category">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="category">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="category">
{% for cat_id, cat_name, cat_thematic, cat_parent_id in category_choices %}
{% if cat_parent_id %}{% ifchanged cat_parent_id %}<div class="filter-option-break"></div>{% endifchanged %}{% endif %}
<div class="filter-option{% if cat_parent_id %} subcategory-option{% endif %}" data-thematic="{{ cat_thematic|default:'' }}" data-category-id="{{ cat_id }}" data-parent-id="{{ cat_parent_id|default:'' }}">
<input type="checkbox" name="category" id="category_{{ cat_id }}" value="{{ cat_id }}" {% if cat_id|stringformat:"s" in selected_categories %}checked{% endif %}>
<label for="category_{{ cat_id }}">{% if cat_parent_id %}<i class="bi bi-arrow-return-right me-1 text-muted small"></i>{% endif %}{{ cat_name }}</label>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Autres filtres en deux colonnes -->
<div class="row mt-3">
<!-- Type de maintenance -->
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Type de maintenance" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="maintain_type">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="maintain_type">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="maintain_type">
{% for key, value, css_class in maintain_type_choices %}
<div class="filter-option">
<input type="checkbox" name="maintain_type" id="maintain_type_{{ key }}" value="{{ key }}" {% if key in selected_maintain_types %}checked{% endif %}>
<label for="maintain_type_{{ key }}" class="context-badge btn-outline-{{ css_class }}">{{ value }}</label>
</div>
{% endfor %}
</div>
</div>
<!-- Type d'intervention -->
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Type d'intervention" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="type">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="type">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="type">
{% for key, value in type_choices %}
<div class="filter-option">
<input type="checkbox" name="type" id="type_{{ key }}" value="{{ key }}" {% if key in selected_types %}checked{% endif %}>
<label for="type_{{ key }}">{{ value }}</label>
</div>
{% endfor %}
</div>
</div>
<!-- Bon de préparation -->
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Bon de préparation (stock)" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="preparation_state">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="preparation_state">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="preparation_state">
<div class="filter-option">
<input type="checkbox" name="preparation_state" id="preparation_state_processed" value="processed" {% if "processed" in selected_preparation_states %}checked{% endif %}>
<label for="preparation_state_processed" class="context-badge btn-outline-success">
<i class="bi bi-check-circle me-1"></i>{% translate "Prêt" %}
</label>
</div>
<div class="filter-option">
<input type="checkbox" name="preparation_state" id="preparation_state_not_processed" value="not_processed" {% if "not_processed" in selected_preparation_states %}checked{% endif %}>
<label for="preparation_state_not_processed" class="context-badge btn-outline-danger">
<i class="bi bi-hourglass me-1"></i>{% translate "En attente" %}
</label>
</div>
<div class="filter-option">
<input type="checkbox" name="preparation_state" id="preparation_state_none" value="none" {% if "none" in selected_preparation_states %}checked{% endif %}>
<label for="preparation_state_none" class="context-badge btn-outline-secondary">
<i class="bi bi-question-circle me-1"></i>{% translate "Aucun bon" %}
</label>
</div>
</div>
</div>
<!-- Priorité -->
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Priorité" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="priority">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="priority">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="priority">
{% for key, value in priority_choices %}
<div class="filter-option">
<input type="checkbox" name="priority" id="priority_{{ key }}" value="{{ key }}" {% if key in selected_priorities %}checked{% endif %}>
<label for="priority_{{ key }}" class="context-badge btn-outline-priority-{{ key }}">{{ value }}</label>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Prestataires / Contrats -->
{% if show_provider_filters %}
<div class="row mt-3">
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Prestataire" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="provider">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="provider">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="provider">
{% for pid, pname, pt_thematics in provider_choices %}
<div class="filter-option" data-thematic-codes="{{ pt_thematics|join:',' }}">
<input type="checkbox" name="provider" id="provider_{{ pid }}" value="{{ pid }}" {% if pid|stringformat:"s" in selected_providers %}checked{% endif %}>
<label for="provider_{{ pid }}">{{ pname }}</label>
</div>
{% endfor %}
</div>
</div>
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Contrat" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="contract">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="contract">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="contract">
{% for cid, cnumber, cprovider, cthematics, cuses_mgr, cmanagers_json in contract_choices %}
<div class="filter-option" data-provider="{{ cprovider }}" data-thematic-codes="{{ cthematics|join:',' }}" data-uses-manager="{{ cuses_mgr|yesno:"true,false" }}" data-managers="{{ cmanagers_json }}">
<input type="checkbox" name="contract" id="contract_{{ cid }}" value="{{ cid }}" {% if cid|stringformat:"s" in selected_contracts %}checked{% endif %}>
<label for="contract_{{ cid }}">{{ cnumber }}</label>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Gestionnaires (dynamic) -->
<div class="row mt-3 d-none" id="intervention-manager-filter-row">
<div class="col-md-12 filter-section">
<div class="filter-section-header">
<label>{% translate "Gestionnaire d'intervention" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="intervention_manager">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="intervention_manager">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="intervention_manager" id="intervention-manager-options-container">
<!-- Dynamic options will be inserted here by JS -->
</div>
</div>
</div>
{% endif %}
<!-- Équipes / Membres assignés -->
<div class="row mt-3">
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Équipe assignée" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="assigned_team">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="assigned_team">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="assigned_team">
{% for tid, tlabel, tcompany, tthematics in team_choices %}
<div class="filter-option" data-company="{{ tcompany }}" data-thematic-codes="{{ tthematics|join:',' }}">
<input type="checkbox" name="assigned_team" id="assigned_team_{{ tid }}" value="{{ tid }}" {% if tid|stringformat:"s" in selected_teams %}checked{% endif %}>
<label for="assigned_team_{{ tid }}">{{ tlabel }}</label>
</div>
{% endfor %}
</div>
</div>
<div class="col-md-6 filter-section">
<div class="filter-section-header">
<label>{% translate "Membre assigné" %}</label>
<div class="filter-section-buttons">
<button type="button" class="btn btn-sm btn-outline-secondary select-all-btn" data-field="assigned_member">{% translate "Tous" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary deselect-all-btn" data-field="assigned_member">{% translate "Aucun" %}</button>
</div>
</div>
<div class="filter-options" data-field="assigned_member">
{% for mid, mlabel, mteam, mcompany, mthematics in member_choices %}
<div class="filter-option" data-team="{{ mteam }}" data-company="{{ mcompany }}" data-thematic-codes="{{ mthematics|join:',' }}">
<input type="checkbox" name="assigned_member" id="assigned_member_{{ mid }}" value="{{ mid }}" {% if mid|stringformat:"s" in selected_members %}checked{% endif %}>
<label for="assigned_member_{{ mid }}">{{ mlabel }}</label>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Localisations (full width) -->
<div class="mt-3 mb-3">
<label class="form-label">{% translate "Localisations" %}</label>
<div id="location-autocomplete-container" class="position-relative">
<input id="location-autocomplete" type="text" class="form-control"
placeholder="{% translate 'Chercher une localisation (min. 2 caractères)…' %}">
</div>
<div id="selected-locations-chips" class="mt-2 d-flex flex-wrap gap-2"></div>
<button id="clear-locations" type="button" class="btn btn-sm btn-outline-secondary mt-2">
{% translate "Effacer les localisations" %}
</button>
</div>
<!-- Dates -->
<div class="row mt-3">
<div class="col-6">
<div>
<label class="form-label">{% translate "Date de début" %}</label>
<div class="d-flex align-items-center gap-2">
<input type="date" name="begin_date_min" id="begin_date_min" class="form-control" placeholder="Min" value="{{ begin_date_min }}">
<span class="mx-1">→</span>
<input type="date" name="begin_date_max" id="begin_date_max" class="form-control" placeholder="Max" value="{{ begin_date_max }}">
</div>
</div>
<div class="mt-3">
<label class="form-label">{% translate "Date de fin" %}</label>
<div class="d-flex align-items-center gap-2">
<input type="date" name="end_date_min" id="end_date_min" class="form-control" placeholder="Min" value="{{ end_date_min }}">
<span class="mx-1">→</span>
<input type="date" name="end_date_max" id="end_date_max" class="form-control" placeholder="Max" value="{{ end_date_max }}">
</div>
</div>
<div class="form-check mt-3">
<input
class="form-check-input"
type="checkbox"
name="overdue"
id="overdue"
value="1"
{% if overdue == '1' %}checked{% endif %}
>
<label class="form-check-label" for="overdue">
{% translate "Interventions non traitées (en retard)" %}
</label>
</div>
<div class="form-check mt-2">
<input
class="form-check-input"
type="checkbox"
name="followed_only"
id="followed_only"
value="1"
{% if followed_only == '1' %}checked{% endif %}
>
<label class="form-check-label" for="followed_only">
{% translate "Interventions suivies uniquement" %}
</label>
</div>
</div>
<div class="col-6"></div>
</div>
{% if to_be_planned_soon %}
<input type="hidden" name="to_be_planned_soon" value="{{ to_be_planned_soon }}">
{% endif %}
</form>
</div>
<div class="modal-footer">
<button type="button" id="reset-filters" class="btn btn-secondary">{% translate "Réinitialiser" %}</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="button" id="apply-filters" class="btn btn-primary">{% translate "Filtrer" %}</button>
</div>
</div>
</div>
</div>
<div class="position-relative">
<!-- Layout selection buttons -->
<div class="position-absolute top-0 end-0 mt-2" style="z-index: 10;">
<div class="btn-group" role="group" aria-label="{% translate 'Sélection de la vue' %}">
<button id="layout-btn-table" class="btn btn-light{% if intervention_list_layout == 'table_only' %} text-primary{% endif %}" type="button" title="{% translate 'Vue tableau uniquement' %}">
<i class="bi bi-table"></i>
</button>
<button id="layout-btn-both" class="btn btn-light{% if intervention_list_layout == 'both' or not intervention_list_layout %} text-primary{% endif %}" type="button" title="{% translate 'Vue partagée' %}">
<i class="bi bi-layout-split"></i>
</button>
<button id="layout-btn-map" class="btn btn-light{% if intervention_list_layout == 'map_only' %} text-primary{% endif %}" type="button" title="{% translate 'Vue carte uniquement' %}">
<i class="bi bi-globe-europe-africa"></i>
</button>
</div>
</div>
<!-- Widget de recherche — centré sur toute la largeur (tableau + carte) -->
<div id="interventions-search-widget"
style="position:absolute; top:4px; left:50%; transform:translateX(-50%); z-index:10; pointer-events:none;">
<div class="input-group" style="pointer-events:auto; flex-wrap:nowrap;">
<!-- Input + bouton X superposé à l'intérieur -->
<div style="position:relative; display:flex;">
<input type="text" id="interventions-search-input" class="form-control form-control-sm"
style="width:320px; border-radius:20px 0 0 20px; border-color:#dee2e6; padding-right:1.6rem;"
placeholder="{% translate 'Titre, code, localisation, contrat…' %}">
<button type="button" id="interventions-search-clear"
style="position:absolute; right:4px; top:50%; transform:translateY(-50%);
background:none; border:none; padding:0 2px; line-height:1;
color:#adb5bd; cursor:pointer; visibility:hidden;"
title="{% translate 'Effacer la recherche' %}">
<i class="bi bi-x-lg" style="font-size:0.7rem;"></i>
</button>
</div>
<span class="input-group-text bg-white px-1" style="border-left:0; border-right:0; border-color:#dee2e6;">
<div class="btn-group btn-group-sm" role="group" aria-label="{% translate 'Mode' %}">
<input type="radio" class="btn-check" name="search-mode" id="search-mode-and" value="and" checked>
<label class="btn btn-outline-secondary py-0 px-2" for="search-mode-and" title="{% translate 'Tous les mots doivent correspondre' %}">{% translate "AND" %}</label>
<input type="radio" class="btn-check" name="search-mode" id="search-mode-or" value="or">
<label class="btn btn-outline-secondary py-0 px-2" for="search-mode-or" title="{% translate 'Au moins un mot doit correspondre' %}">{% translate "OR" %}</label>
</div>
</span>
<button class="btn btn-sm" type="button" id="interventions-search-btn"
style="border-radius:0 20px 20px 0; border:1px solid #dee2e6; border-left:0; background:white; color:#495057;"
title="{% translate 'Rechercher' %}">
<i class="bi bi-search"></i>
</button>
</div>
</div>
<div class="row mt-2" style="height: calc(100vh - 110px);">
<div class="{% if intervention_list_layout == 'map_only' %}d-none{% elif intervention_list_layout == 'table_only' %}col-12{% else %}col-md-6{% endif %}" id="col-left" style="max-height: calc(100vh - 110px); ">
<ul class="nav nav-tabs" id="tablesTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="interventions-table-tab" data-bs-toggle="tab" data-bs-target="#interventions-table-content" type="button" role="tab" aria-controls="interventions-table" aria-selected="true">{% translate "Interventions" %}</button>
</li>
<div class="my-1 ms-2">
<button class="btn btn-light" type="button" data-bs-toggle="modal" data-bs-target="#interventionTypeModal">
<i class="bi bi-plus-circle"></i>
</button>
</div>
</ul>
<div class="tab-content d-flex flex-column" id="tablesTabContent" style="flex: 1; min-height: 0;">
<div class="tab-pane fade show active d-flex flex-column" id="interventions-table-content" role="tabpanel" aria-labelledby="interventions-table-tab" style="flex: 1; min-height: 0;">
<div class="d-flex justify-content-between flex-wrap align-items-center gap-2 mb-2 mt-2">
<!-- Bloc gauche : selection -->
<div class="d-flex gap-2 flex-wrap align-items-center">
<button type="button" class="btn btn-sm btn-outline-secondary" id="select-all">{% translate "Tout sélectionner" %}</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="deselect-all">{% translate "Tout désélectionner" %}</button>
<div id="selection-status" class="text-muted small mb-0">
{% blocktranslate count count=selected_interventions_ids|length %}
{{ count }} intervention sélectionnée
{% plural %}
{{ count }} interventions sélectionnées
{% endblocktranslate %}
</div>
</div>
<!-- Bloc droite : action -->
<div class="dropdown" id="bulk-action-dropdown">
<button class="btn btn-light btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
{% translate "Action" %}
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="#" data-action="status-change">
<i class="bi bi-fast-forward-circle me-2"></i></i>{% translate "Modifier le statut" %}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-action="associate-order">
<i class="bi bi-link-45deg me-2"></i>{% translate "Associer à une commande" %}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-action="export" data-bs-toggle="modal" data-bs-target="#exportModal">
<i class="bi bi-download me-2"></i>{% translate "Exporter" %}
</a>
</li>
{% if is_admin %}
<li>
<a class="dropdown-item" href="#" data-action="export-sheets-zip">
<i class="bi bi-file-earmark-zip me-2"></i>{% translate "Exporter les fiches (ZIP)" %}
</a>
</li>
{% endif %}
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="#" data-action="execution-report" data-bs-toggle="modal" data-bs-target="#executionReportModal">
<i class="bi bi-file-earmark-text me-2"></i>{% translate "Rapport d'exécution (PDF)" %}
</a>
</li>
</ul>
</div>
</div>
<!-- Spinner -->
<div id="interventions-spinner" class="table-spinner">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">{% translate "Chargement..." %}</span>
</div>
</div>
<div id="interventions-table-container" style="display: none; flex: 1; min-height: 0; overflow: hidden;">
<!-- Bouton de filtre -->
<div id="filter-dropdown-wrapper" class="float-left mb-2">
<button class="btn btn-light position-relative" type="button" data-bs-toggle="modal" data-bs-target="#filterModal">
<i class="bi bi-funnel"></i> {% translate "Filtre" %}
<span id="filter-badge" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-black d-none">
<span id="filter-count">0</span>
</span>
</button>
<!-- Alerte limite atteinte (cachée par défaut) -->
<span id="filter-limit-alert" class="alert alert-info py-1 px-2 ms-2 d-none align-middle" role="alert">
<i class="bi bi-info-circle me-1"></i>
{% translate "Contenu limité à 5 000 éléments." %}"
</span>
</div>
<table id="interventions-table" class="table" style="margin-bottom: 0;"
data-pagination="true"
data-page-size="50"
data-click-to-select="true"
data-show-columns="true"
data-unique-id="id" >
</table>
</div>
</div>
</div>
</div>
<div class="{% if intervention_list_layout == 'table_only' %}d-none{% elif intervention_list_layout == 'map_only' %}col-12{% else %}col-md-6{% endif %}" id="col-right">
<div id="map" class="rounded-2" style="height: calc(100vh - 210px); margin-top: 50px;">
<button id="filterzone" class="btn btn-light btn-sm d-flex mx-auto mt-1 " type="button">
{% translate "Filtrer sur cette zone" %}
</button>
</div>
</div>
</div>
</div>
<!-- Modale pour le changement de staut -->
<div class="modal fade" id="statusChangeModal" tabindex="-1" aria-labelledby="statusChangeModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="statusChangeModalLabel">{% translate "Changer le statut des interventions" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body">
<div id="status-change-selection-info" class="alert alert-info d-none mb-3" role="alert">
<i class="bi bi-info-circle me-1"></i>
{% translate "Aucune intervention sélectionnée : le changement de statut s'appliquera à toutes les interventions filtrées." %}
</div>
<div class="mb-3">
<label for="new-status" class="form-label">{% translate "Nouveau statut" %}</label>
<select class="form-select" id="new-status">
<option value="">{% translate "-- Choisir un statut --" %}</option>
{% if is_admin %}
{% for key, value, css_class in status_choices %}
<option value="{{ key }}">{{ value }}</option>
{% endfor %}
{% else %}
<option value="to_be_approved">{% translate "À approuver" %}</option>
<option value="to_be_planned">{% translate "À planifier" %}</option>
<option value="to_be_processed">{% translate "À traiter" %}</option>
<option value="validated">{% translate "Validé" %}</option>
<option value="canceled">{% translate "Annulé" %}</option>
{% endif %}
</select>
</div>
<div id="cancellation-reason-group" class="mb-3 d-none">
<label for="bulk-cancellation-type" class="form-label">{% translate "Type d'annulation" %} <span class="text-danger">*</span></label>
<select class="form-select mb-2" id="bulk-cancellation-type">
<option value="" selected disabled>{% translate "Choisissez un type" %}</option>
<option value="duplicate">{% translate "Doublon" %}</option>
<option value="to_redirect">{% translate "A rediriger" %}</option>
<option value="not_our_assets">{% translate "Pas sous notre gestion" %}</option>
<option value="non_relevant">{% translate "Non-relevant" %}</option>
<option value="other">{% translate "Autre" %}</option>
</select>
<label for="bulk-cancellation-reason" class="form-label">{% translate "Commentaire" %} <span class="text-danger d-none" id="bulkCancellationReasonRequired">*</span></label>
<textarea class="form-control" id="bulk-cancellation-reason" rows="3" maxlength="1000" placeholder="{% translate 'Commentaire libre...' %}"></textarea>
<small class="form-text text-muted">{% translate "Obligatoire pour le motif \"Autre\". Sinon, le motif choisi sera enregistré comme note." %}</small>
</div>
<div id="status-error-message" class="alert alert-danger d-none" role="alert"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="button" class="btn btn-primary" id="confirm-status-change">{% translate "Confirmer" %}</button>
</div>
</div>
</div>
</div>
<!-- Modale pour associer à une commande -->
<div class="modal fade" id="associateOrderModal" tabindex="-1" aria-labelledby="associateOrderModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="associateOrderModalLabel">{% translate "Associer les interventions à une commande" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body">
<div id="associate-order-selection-info" class="alert alert-info d-none mb-3" role="alert">
<i class="bi bi-info-circle me-1"></i>
{% translate "Aucune intervention sélectionnée : l'association s'appliquera à toutes les interventions filtrées." %}
</div>
<div class="mb-3">
<label for="order-search" class="form-label">{% translate "Commande" %}</label>
<input type="text" id="order-search" class="form-control" placeholder="{% translate 'Rechercher une commande...' %}">
<input type="hidden" id="order-id" value="">
<div class="form-text">{% translate "Seules les commandes au statut 'En préparation' ou 'Envoyé' et auxquelles vous avez accès sont proposées." %}</div>
</div>
<div id="associate-order-error" class="alert alert-danger d-none" role="alert"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="button" class="btn btn-primary" id="confirm-associate-order">{% translate "Associer" %}</button>
</div>
</div>
</div>
</div>
<!-- Modal Export -->
<div class="modal fade" id="exportModal" tabindex="-1" aria-labelledby="exportModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exportModalLabel">{% translate "Exporter les interventions sélectionnées" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body">
<div id="export-selection-info" class="alert alert-info d-none mb-3" role="alert">
<i class="bi bi-info-circle me-1"></i>
{% translate "Aucune intervention sélectionnée : l'export inclura toutes les interventions filtrées." %}
</div>
<p class="small text-muted">{% translate "Choisissez le format de fichier à générer." %}</p>
<div class="d-flex gap-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="export-format" id="export-format-csv" value="csv" checked>
<label class="form-check-label" for="export-format-csv">CSV</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="export-format" id="export-format-xlsx" value="xlsx">
<label class="form-check-label" for="export-format-xlsx">Excel (XLSX)</label>
</div>
</div>
<div id="export-error" class="alert alert-danger d-none mt-3" role="alert"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="button" class="btn btn-primary" id="confirm-export-btn">{% translate "Exporter" %}</button>
</div>
</div>
</div>
</div>
<!-- Modal Rapport d'exécution -->
<div class="modal fade" id="executionReportModal" tabindex="-1" aria-labelledby="executionReportModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="executionReportModalLabel"><i class="bi bi-file-earmark-text me-2"></i>{% translate "Rapport d'exécution" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
</div>
<div class="modal-body">
<div id="execution-report-selection-info" class="alert alert-info d-none mb-3" role="alert">
<i class="bi bi-info-circle me-1"></i>
{% translate "Aucune intervention sélectionnée : toutes les interventions filtrées seront incluses dans le rapport." %}
</div>
<div id="execution-report-too-many" class="alert alert-warning d-none mb-3" role="alert">
<i class="bi bi-exclamation-triangle me-1"></i>
{% translate "Vous avez sélectionné plus de 50 interventions. Veuillez réduire votre sélection avant de générer le rapport." %}
</div>
<div class="mb-3">
<label for="execution-report-title" class="form-label fw-semibold">{% translate "Titre du rapport" %}</label>
<input type="text" class="form-control" id="execution-report-title"
placeholder="{% translate 'Ex : Rapport mensuel – Voirie avril 2026' %}" maxlength="120">
<div class="form-text">{% translate "Optionnel. Apparaîtra en tête avant le sommaire." %}</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">{% translate "Période (changement de statut)" %}</label>
<div class="input-group">
<span class="input-group-text">{% translate "Du" %}</span>
<input type="date" class="form-control" id="execution-report-date-from">
<span class="input-group-text">{% translate "Au" %}</span>
<input type="date" class="form-control" id="execution-report-date-to">
</div>
<div class="form-text">{% translate "Optionnel. Filtre sur la date de changement de statut de l'intervention." %}</div>
</div>
<p class="small text-muted mb-0">{% translate "Le rapport reprendra les interventions correspondant aux filtres actifs." %}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="button" class="btn btn-primary" id="confirm-execution-report-btn">
<i class="bi bi-file-earmark-pdf me-1"></i>{% translate "Télécharger le PDF" %}
</button>
</div>
</div>
</div>
</div>
<!-- Overlay de progression pour la génération du rapport d'exécution -->
<div id="execution-report-progress-overlay"
class="position-fixed top-0 start-0 w-100 h-100"
style="display:none; background:rgba(0,0,0,.55); z-index:9050; align-items:center; justify-content:center;">
<div class="card shadow-lg border-0 rounded-3" style="max-width:440px; width:90%;">
<div class="card-body text-center p-4 p-md-5">
<i class="bi bi-file-earmark-pdf text-primary mb-3" style="font-size:2.75rem;"></i>
<h6 class="fw-semibold mb-1">{% translate "Génération du rapport en cours…" %}</h6>
<p id="execution-report-progress-label" class="text-muted small mb-3">&nbsp;</p>
<div class="progress rounded-pill mb-1" style="height:12px;">
<div id="execution-report-progress-bar"
class="progress-bar bg-primary"
role="progressbar"
style="width:0%; transition:width .4s ease;"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<p id="execution-report-progress-pct" class="text-muted small mb-0">0&nbsp;%</p>
</div>
</div>
</div>
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1100">
<div id="app-toast" class="toast align-items-center text-white bg-success border-0" role="alert" aria-live="polite" aria-atomic="true">
<div class="d-flex">
<div id="app-toast-body" class="toast-body">
<!-- Message injecté dynamiquement -->
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Fermer"></button>
</div>
</div>
</div>
{% endblock content%}
{% block script %}
<!-- Mapbox GL Draw 1.5.0 (local) -->
<script src="{% static 'common/mapbox-gl-draw.js' %}"></script>
<!-- Turf.js (local) -->
<script src="{% static 'common/turf.min.js' %}"></script>
<!-- jQuery UI 1.14.1 (local) -->
<link rel="stylesheet" href="{% static 'common/jquery-ui.min.css' %}">
<script src="{% static 'common/jquery-ui.min.js' %}"></script>
<script>
const interventionsgeojsonUrl = "{% url 'interventions:interventions_geojson' %}";
const interventionsurl = "{% url 'interventions:interventions_index' %}";
const locationsAutocompleteUrl = "{% url 'assets:locations_autocomplete' %}";
const availableOrdersUrl = "{% url 'interventions:available_orders' %}";
const bulkAssociateOrderUrl = "{% url 'interventions:bulk_associate_order' %}";
const exportInterventionsUrl = "{% url 'interventions:export_interventions' %}";
const exportSheetsZipUrl = "{% url 'interventions:export_intervention_sheets_zip' %}";
const executionReportUrl = "{% url 'interventions:bulk_execution_report_pdf' %}";
const executionReportStartUrl = "{% url 'interventions:start_bulk_execution_report' %}";
const executionReportPollBaseUrl = "{% url 'interventions:poll_bulk_execution_report' token='__TOKEN__' %}";
const executionReportDownloadBaseUrl = "{% url 'interventions:download_bulk_execution_report' token='__TOKEN__' %}";
const saveLayoutUrl = "{% url 'common:save_intervention_list_layout' %}";
const savePreferencesUrl = "{% url 'common:save_intervention_list_preferences' %}";
var selected_interventions_set = new Set(JSON.parse('{{ selected_interventions_ids|default:"[]"|escapejs }}'));
const PRESELECTED_LOCATIONS = JSON.parse('{{ preselected_locations|default:"[]"|escapejs }}');
const INITIAL_LAYOUT = '{{ intervention_list_layout|default:"both" }}';
const SAVED_SORT = {{ saved_sort|default:"{}"|safe }};
const SAVED_COLUMNS = {{ saved_columns|default:"null"|safe }};
const subcatNoneLabel = "{% translate '(aucune sous-catégorie)' %}";
</script>
<script src="{% url 'javascript-catalog' %}"></script>
<script src="{% static 'common/base_script.js' %}"></script>
<script src="{% static 'common/base_map.js' %}"></script>
<script src="{% static 'interventions/status_colors.js' %}"></script>
<script src="{% static 'interventions/interventions_index.js' %}"></script>
{% endblock script %}