feat: implement unified asset index view with dynamic filtering modal and associated JavaScript logic
This commit is contained in:
parent
2b8cdfabb7
commit
d82dcde16d
2 changed files with 448 additions and 288 deletions
|
|
@ -1171,14 +1171,14 @@ $(document).ready(function () {
|
||||||
document.getElementById('col-table').className = 'col-md-6';
|
document.getElementById('col-table').className = 'col-md-6';
|
||||||
const colMap = document.getElementById('col-map');
|
const colMap = document.getElementById('col-map');
|
||||||
colMap.className = 'col-md-6';
|
colMap.className = 'col-md-6';
|
||||||
colMap.style.cssText = 'position: relative; margin-top: 44px;';
|
colMap.style.cssText = 'position: relative; margin-top: 50px;';
|
||||||
setLayoutActive('both');
|
setLayoutActive('both');
|
||||||
});
|
});
|
||||||
document.getElementById('layout-btn-map').addEventListener('click', function () {
|
document.getElementById('layout-btn-map').addEventListener('click', function () {
|
||||||
document.getElementById('col-table').classList.add('d-none');
|
document.getElementById('col-table').classList.add('d-none');
|
||||||
const colMap = document.getElementById('col-map');
|
const colMap = document.getElementById('col-map');
|
||||||
colMap.className = 'col-12';
|
colMap.className = 'col-12';
|
||||||
colMap.style.cssText = 'position: relative; margin-top: 44px;';
|
colMap.style.cssText = 'position: relative; margin-top: 50px;';
|
||||||
setLayoutActive('map');
|
setLayoutActive('map');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,74 +3,163 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link href="{% static 'common/mapbox-gl-draw.css' %}" rel="stylesheet"/>
|
<link href="{% static 'common/mapbox-gl-draw.css' %}" rel="stylesheet" />
|
||||||
<link rel="stylesheet" href="{% static 'assets/assets_index.css' %}">
|
<link rel="stylesheet" href="{% static 'assets/assets_index.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'assets/info-panel.css' %}">
|
<link rel="stylesheet" href="{% static 'assets/info-panel.css' %}">
|
||||||
<style>
|
<style>
|
||||||
#assets-search-input:focus { outline: none; box-shadow: none; border-color: #dee2e6; }
|
#assets-search-input:focus {
|
||||||
#unified-empty-state { display: none; color: #6c757d; }
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border-color: #dee2e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#unified-empty-state {
|
||||||
|
display: none;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
/* ─── Filter modal ──────────────────────────────────── */
|
/* ─── Filter modal ──────────────────────────────────── */
|
||||||
#filterModal .modal-dialog { max-width: 95%; }
|
#filterModal .modal-dialog {
|
||||||
#filterModal .modal-content { display: flex; flex-direction: column; max-height: 90vh; }
|
max-width: 95%;
|
||||||
#filterModal .modal-body { flex: 1; overflow-y: auto; }
|
}
|
||||||
#filterModal .modal-footer { flex-shrink: 0; }
|
|
||||||
.filter-section { margin-bottom: 1rem; }
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
.filter-section-header {
|
.filter-section-header {
|
||||||
display: flex; justify-content: space-between; align-items: center;
|
display: flex;
|
||||||
margin-bottom: 0.75rem; gap: 1rem;
|
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-header>label {
|
||||||
.filter-section-buttons button { padding: 0.25rem 0.5rem; font-size: 0.75rem; white-space: nowrap; }
|
font-weight: 600;
|
||||||
.filter-options {
|
color: #333;
|
||||||
display: flex; flex-wrap: wrap; gap: 0.5rem; min-height: 2.5rem;
|
margin: 0;
|
||||||
padding: 0.5rem; background-color: #f8f9fa;
|
flex-shrink: 0;
|
||||||
border-radius: 0.375rem; border: 1px solid #dee2e6;
|
|
||||||
}
|
}
|
||||||
.filter-option { display: flex; align-items: center; }
|
|
||||||
.filter-option input[type="checkbox"],
|
.filter-section-buttons {
|
||||||
.filter-option input[type="radio"] {
|
display: flex;
|
||||||
position: absolute; opacity: 0; width: 0; height: 0; cursor: pointer;
|
gap: 0.5rem;
|
||||||
|
margin-left: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.filter-option label {
|
|
||||||
display: inline-flex; align-items: center; justify-content: center;
|
.filter-section-buttons button {
|
||||||
margin: 0; font-weight: 500; cursor: pointer;
|
padding: 0.25rem 0.5rem;
|
||||||
background-color: #e7f1ff; color: #0c5cc9;
|
font-size: 0.75rem;
|
||||||
border-radius: 1rem; padding: 0.35rem 0.75rem; font-size: 0.8rem;
|
|
||||||
border: 1px solid #b8d4f1; transition: all 0.15s ease;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.filter-option input[type="checkbox"]:checked + label,
|
|
||||||
.filter-option input[type="radio"]:checked + label {
|
.filter-options {
|
||||||
background-color: #0c5cc9; color: #fff; border-color: #0c5cc9;
|
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 label:hover { background-color: #cfe2f3; }
|
|
||||||
.filter-option input:checked + label:hover { background-color: #0a4fb0; }
|
.filter-option {
|
||||||
.filter-option input:disabled + label { opacity: 0.5; cursor: not-allowed; }
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-option input[type="checkbox"],
|
||||||
|
.filter-option input[type="radio"] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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.35rem 0.75rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
border: 1px solid #b8d4f1;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-option input[type="checkbox"]:checked+label,
|
||||||
|
.filter-option input[type="radio"]:checked+label {
|
||||||
|
background-color: #0c5cc9;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #0c5cc9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-option label:hover {
|
||||||
|
background-color: #cfe2f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-option input:checked+label:hover {
|
||||||
|
background-color: #0a4fb0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-option input:disabled+label {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
#map .maplibregl-popup-close-button {
|
#map .maplibregl-popup-close-button {
|
||||||
font-size: 1.35rem;
|
font-size: 1.35rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
padding: 0.2rem 0.45rem;
|
padding: 0.2rem 0.45rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unified-add-panel {
|
.unified-add-panel {
|
||||||
border: 1px solid #dee2e6;
|
border: 1px solid #dee2e6;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unified-add-panel h6 {
|
.unified-add-panel h6 {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unified-add-panel .form-select,
|
.unified-add-panel .form-select,
|
||||||
.unified-add-panel .form-control {
|
.unified-add-panel .form-control {
|
||||||
border-radius: 0.65rem;
|
border-radius: 0.65rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#map .maplibregl-ctrl-top-right,
|
#map .maplibregl-ctrl-top-right,
|
||||||
#map .mapboxgl-ctrl-top-right {
|
#map .mapboxgl-ctrl-top-right {
|
||||||
top: 10px !important;
|
top: 10px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
@ -81,7 +170,8 @@
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les assets" %}</h5>
|
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les assets" %}</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||||
|
aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
|
|
@ -90,19 +180,21 @@
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Thématique" %}</label>
|
<label>{% translate "Thématique" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="thematic-select-all">{% translate "Tous" %}</button>
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="thematic-select-all">{%
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="thematic-deselect-all">{% translate "Aucun" %}</button>
|
translate "Tous" %}</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="thematic-deselect-all">{%
|
||||||
|
translate "Aucun" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
{% for thematic in accessible_thematics %}
|
{% for thematic in accessible_thematics %}
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="checkbox" class="thematic-checkbox"
|
<input type="checkbox" class="thematic-checkbox" id="thematic-cb-{{ thematic.code }}"
|
||||||
id="thematic-cb-{{ thematic.code }}"
|
value="{{ thematic.code }}" {% if thematic.code in selected_thematics %}checked{% endif
|
||||||
value="{{ thematic.code }}"
|
%}>
|
||||||
{% if thematic.code in selected_thematics %}checked{% endif %}>
|
|
||||||
<label for="thematic-cb-{{ thematic.code }}">
|
<label for="thematic-cb-{{ thematic.code }}">
|
||||||
{% if thematic.icon %}<i class="bi {{ thematic.icon }} me-1"></i>{% endif %}{{ thematic.name }}
|
{% if thematic.icon %}<i class="bi {{ thematic.icon }} me-1"></i>{% endif %}{{
|
||||||
|
thematic.name }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
@ -114,12 +206,15 @@
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Catégorie" %}</label>
|
<label>{% translate "Catégorie" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="category-select-all">{% translate "Toutes" %}</button>
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="category-select-all">{%
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="category-deselect-all">{% translate "Aucune" %}</button>
|
translate "Toutes" %}</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="category-deselect-all">{%
|
||||||
|
translate "Aucune" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="category-filter-options" class="filter-options">
|
<div id="category-filter-options" class="filter-options">
|
||||||
<span class="text-muted small">{% translate "Sélectionnez d'abord une ou plusieurs thématiques." %}</span>
|
<span class="text-muted small">{% translate "Sélectionnez d'abord une ou plusieurs thématiques."
|
||||||
|
%}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -128,13 +223,17 @@
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Modèle" %}</label>
|
<label>{% translate "Modèle" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="model-select-all">{% translate "Tous" %}</button>
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="model-select-all">{%
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="model-deselect-all">{% translate "Aucun" %}</button>
|
translate "Tous" %}</button>
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary d-none" id="model-filter-toggle"></button>
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="model-deselect-all">{%
|
||||||
|
translate "Aucun" %}</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary d-none"
|
||||||
|
id="model-filter-toggle"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="model-filter-options" class="filter-options">
|
<div id="model-filter-options" class="filter-options">
|
||||||
<span class="text-muted small">{% translate "Sélectionnez d'abord une ou plusieurs catégories." %}</span>
|
<span class="text-muted small">{% translate "Sélectionnez d'abord une ou plusieurs catégories."
|
||||||
|
%}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -144,7 +243,8 @@
|
||||||
<label>{% translate "Filtres thématiques" %}</label>
|
<label>{% translate "Filtres thématiques" %}</label>
|
||||||
</div>
|
</div>
|
||||||
<div id="conditional-filter-options" class="filter-options">
|
<div id="conditional-filter-options" class="filter-options">
|
||||||
<span class="text-muted small">{% translate "Sélectionnez d'abord une ou plusieurs thématiques." %}</span>
|
<span class="text-muted small">{% translate "Sélectionnez d'abord une ou plusieurs thématiques."
|
||||||
|
%}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -155,21 +255,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="radio" name="unified-type-filter" id="type-all" value="all"
|
<input type="radio" name="unified-type-filter" id="type-all" value="all" {% if
|
||||||
{% if preventive_element_type != 'assets' and preventive_element_type != 'locations' %}checked{% endif %}
|
preventive_element_type !='assets' and preventive_element_type !='locations' %}checked{%
|
||||||
{% if preventive_element_type %}disabled{% endif %}>
|
endif %} {% if preventive_element_type %}disabled{% endif %}>
|
||||||
<label for="type-all">{% translate "Assets et localisations" %}</label>
|
<label for="type-all">{% translate "Assets et localisations" %}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="radio" name="unified-type-filter" id="type-locations" value="locations"
|
<input type="radio" name="unified-type-filter" id="type-locations" value="locations" {% if
|
||||||
{% if preventive_element_type == 'locations' %}checked{% endif %}
|
preventive_element_type=='locations' %}checked{% endif %} {% if preventive_element_type
|
||||||
{% if preventive_element_type %}disabled{% endif %}>
|
%}disabled{% endif %}>
|
||||||
<label for="type-locations">{% translate "Localisations uniquement" %}</label>
|
<label for="type-locations">{% translate "Localisations uniquement" %}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="radio" name="unified-type-filter" id="type-assets" value="assets"
|
<input type="radio" name="unified-type-filter" id="type-assets" value="assets" {% if
|
||||||
{% if preventive_element_type == 'assets' %}checked{% endif %}
|
preventive_element_type=='assets' %}checked{% endif %} {% if preventive_element_type
|
||||||
{% if preventive_element_type %}disabled{% endif %}>
|
%}disabled{% endif %}>
|
||||||
<label for="type-assets">{% translate "Assets uniquement" %}</label>
|
<label for="type-assets">{% translate "Assets uniquement" %}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -197,7 +297,8 @@
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
{% for status_value, status_label in asset_status_choices %}
|
{% for status_value, status_label in asset_status_choices %}
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="checkbox" name="filter-status" id="filter-status-{{ status_value }}" value="{{ status_value }}">
|
<input type="checkbox" name="filter-status" id="filter-status-{{ status_value }}"
|
||||||
|
value="{{ status_value }}">
|
||||||
<label for="filter-status-{{ status_value }}">{{ status_label }}</label>
|
<label for="filter-status-{{ status_value }}">{{ status_label }}</label>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
@ -212,10 +313,14 @@
|
||||||
<label>{% translate "Statut de validation" %}</label>
|
<label>{% translate "Statut de validation" %}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
{% for validation_status_value, validation_status_label in asset_validation_status_choices %}
|
{% for validation_status_value, validation_status_label in asset_validation_status_choices
|
||||||
|
%}
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="checkbox" name="filter-validation-status" id="filter-validation-status-{{ validation_status_value }}" value="{{ validation_status_value }}">
|
<input type="checkbox" name="filter-validation-status"
|
||||||
<label for="filter-validation-status-{{ validation_status_value }}">{{ validation_status_label }}</label>
|
id="filter-validation-status-{{ validation_status_value }}"
|
||||||
|
value="{{ validation_status_value }}">
|
||||||
|
<label for="filter-validation-status-{{ validation_status_value }}">{{
|
||||||
|
validation_status_label }}</label>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -224,8 +329,10 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" id="reset-filters" class="btn btn-secondary">{% translate "Réinitialiser" %}</button>
|
<button type="button" id="reset-filters" class="btn btn-secondary">{% translate "Réinitialiser"
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
%}</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>
|
<button type="button" id="apply-filters" class="btn btn-primary">{% translate "Filtrer" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -233,12 +340,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# ─── Add chooser modal ────────────────────────────────────────────────────── #}
|
{# ─── Add chooser modal ────────────────────────────────────────────────────── #}
|
||||||
<div class="modal fade" id="unifiedAddChooserModal" tabindex="-1" aria-labelledby="unifiedAddChooserModalLabel" aria-hidden="true">
|
<div class="modal fade" id="unifiedAddChooserModal" tabindex="-1" aria-labelledby="unifiedAddChooserModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="unifiedAddChooserModalLabel">{% translate "Créer un élément" %}</h5>
|
<h5 class="modal-title" id="unifiedAddChooserModalLabel">{% translate "Créer un élément" %}</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||||
|
aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div id="unified-add-chooser-alert" class="alert alert-info small mb-3">
|
<div id="unified-add-chooser-alert" class="alert alert-info small mb-3">
|
||||||
|
|
@ -247,8 +356,10 @@
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="unified-add-panel h-100">
|
<div class="unified-add-panel h-100">
|
||||||
<h6 class="d-flex align-items-center gap-2"><i class="bi bi-layers"></i>{% translate "Asset" %}</h6>
|
<h6 class="d-flex align-items-center gap-2"><i class="bi bi-layers"></i>{% translate "Asset"
|
||||||
<label for="unified-add-asset-thematic" class="form-label small text-muted mb-1">{% translate "Thématique" %}</label>
|
%}</h6>
|
||||||
|
<label for="unified-add-asset-thematic" class="form-label small text-muted mb-1">{%
|
||||||
|
translate "Thématique" %}</label>
|
||||||
<select id="unified-add-asset-thematic" class="form-select mb-3"></select>
|
<select id="unified-add-asset-thematic" class="form-select mb-3"></select>
|
||||||
<button type="button" id="unified-add-asset-open" class="btn btn-primary w-100">
|
<button type="button" id="unified-add-asset-open" class="btn btn-primary w-100">
|
||||||
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer un asset" %}
|
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer un asset" %}
|
||||||
|
|
@ -257,8 +368,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="unified-add-panel h-100">
|
<div class="unified-add-panel h-100">
|
||||||
<h6 class="d-flex align-items-center gap-2"><i class="bi bi-geo-alt"></i>{% translate "Localisation" %}</h6>
|
<h6 class="d-flex align-items-center gap-2"><i class="bi bi-geo-alt"></i>{% translate
|
||||||
<label for="unified-add-location-thematic" class="form-label small text-muted mb-1">{% translate "Thématique" %}</label>
|
"Localisation" %}</h6>
|
||||||
|
<label for="unified-add-location-thematic" class="form-label small text-muted mb-1">{%
|
||||||
|
translate "Thématique" %}</label>
|
||||||
<select id="unified-add-location-thematic" class="form-select mb-3"></select>
|
<select id="unified-add-location-thematic" class="form-select mb-3"></select>
|
||||||
<button type="button" id="unified-add-location-open" class="btn btn-outline-primary w-100">
|
<button type="button" id="unified-add-location-open" class="btn btn-outline-primary w-100">
|
||||||
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer une localisation" %}
|
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer une localisation" %}
|
||||||
|
|
@ -275,39 +388,46 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# ─── Asset create modal ──────────────────────────────────────────────────── #}
|
{# ─── Asset create modal ──────────────────────────────────────────────────── #}
|
||||||
<div class="modal fade" id="unifiedAddAssetModal" tabindex="-1" aria-labelledby="unifiedAddAssetModalLabel" aria-hidden="true">
|
<div class="modal fade" id="unifiedAddAssetModal" tabindex="-1" aria-labelledby="unifiedAddAssetModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||||
<form id="unifiedAddAssetForm" class="modal-content">
|
<form id="unifiedAddAssetForm" class="modal-content">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="thematic_code" id="unified-add-asset-thematic-code">
|
<input type="hidden" name="thematic_code" id="unified-add-asset-thematic-code">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="unifiedAddAssetModalLabel">{% translate "Créer un asset" %}</h5>
|
<h5 class="modal-title" id="unifiedAddAssetModalLabel">{% translate "Créer un asset" %}</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||||
|
aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div id="unifiedAddAssetAlert" class="alert d-none" role="alert"></div>
|
<div id="unifiedAddAssetAlert" class="alert d-none" role="alert"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="unifiedAddAssetCategory" class="form-label">{% translate "Catégorie" %} <span class="text-danger">*</span></label>
|
<label for="unifiedAddAssetCategory" class="form-label">{% translate "Catégorie" %} <span
|
||||||
|
class="text-danger">*</span></label>
|
||||||
<select class="form-select" id="unifiedAddAssetCategory" name="category_id" required>
|
<select class="form-select" id="unifiedAddAssetCategory" name="category_id" required>
|
||||||
<option value="">{% translate "Sélectionner une catégorie..." %}</option>
|
<option value="">{% translate "Sélectionner une catégorie..." %}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="unifiedAddAssetModel" class="form-label">{% translate "Modèle" %} <span class="text-danger">*</span></label>
|
<label for="unifiedAddAssetModel" class="form-label">{% translate "Modèle" %} <span
|
||||||
|
class="text-danger">*</span></label>
|
||||||
<select class="form-select" id="unifiedAddAssetModel" name="model_id" required disabled>
|
<select class="form-select" id="unifiedAddAssetModel" name="model_id" required disabled>
|
||||||
<option value="">{% translate "Sélectionner d'abord une catégorie..." %}</option>
|
<option value="">{% translate "Sélectionner d'abord une catégorie..." %}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3 d-none" id="unifiedAddAssetLocationGroup">
|
<div class="mb-3 d-none" id="unifiedAddAssetLocationGroup">
|
||||||
<label for="unifiedAddAssetLocation" class="form-label">{% translate "Localisation" %} <span class="text-danger">*</span></label>
|
<label for="unifiedAddAssetLocation" class="form-label">{% translate "Localisation" %} <span
|
||||||
|
class="text-danger">*</span></label>
|
||||||
<select class="form-select" id="unifiedAddAssetLocation" name="location_id" disabled>
|
<select class="form-select" id="unifiedAddAssetLocation" name="location_id" disabled>
|
||||||
<option value="">{% translate "Chargement..." %}</option>
|
<option value="">{% translate "Chargement..." %}</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="form-text text-muted" id="unifiedAddAssetLocationHelp"></div>
|
<div class="form-text text-muted" id="unifiedAddAssetLocationHelp"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3" id="unifiedAddAssetCodeGroup">
|
<div class="mb-3" id="unifiedAddAssetCodeGroup">
|
||||||
<label for="unifiedAddAssetCode" class="form-label">{% translate "Code" %} <span class="text-danger">*</span></label>
|
<label for="unifiedAddAssetCode" class="form-label">{% translate "Code" %} <span
|
||||||
<input type="text" class="form-control" id="unifiedAddAssetCode" name="code" maxlength="50" required>
|
class="text-danger">*</span></label>
|
||||||
|
<input type="text" class="form-control" id="unifiedAddAssetCode" name="code" maxlength="50"
|
||||||
|
required>
|
||||||
<div class="form-text text-muted d-none" id="unifiedAddAssetCodeHelp"></div>
|
<div class="form-text text-muted d-none" id="unifiedAddAssetCodeHelp"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
|
@ -319,11 +439,13 @@
|
||||||
<input type="text" class="form-control" id="unifiedAddAssetNameNl" name="name_nl" maxlength="200">
|
<input type="text" class="form-control" id="unifiedAddAssetNameNl" name="name_nl" maxlength="200">
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-info small mb-0">
|
<div class="alert alert-info small mb-0">
|
||||||
<i class="bi bi-info-circle me-1"></i>{% translate "L'asset sera créé avec le statut 'À approuver'." %}
|
<i class="bi bi-info-circle me-1"></i>{% translate "L'asset sera créé avec le statut 'À approuver'."
|
||||||
|
%}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler"
|
||||||
|
%}</button>
|
||||||
<button type="submit" class="btn btn-primary" id="unifiedAddAssetSubmit">
|
<button type="submit" class="btn btn-primary" id="unifiedAddAssetSubmit">
|
||||||
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer l'asset" %}
|
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer l'asset" %}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -333,7 +455,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# ─── Location create modal ───────────────────────────────────────────────── #}
|
{# ─── Location create modal ───────────────────────────────────────────────── #}
|
||||||
<div class="modal fade" id="unifiedAddLocationModal" tabindex="-1" aria-labelledby="unifiedAddLocationModalLabel" aria-hidden="true">
|
<div class="modal fade" id="unifiedAddLocationModal" tabindex="-1" aria-labelledby="unifiedAddLocationModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||||
<form id="unifiedAddLocationForm" class="modal-content">
|
<form id="unifiedAddLocationForm" class="modal-content">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
@ -341,7 +464,8 @@
|
||||||
<input type="hidden" id="unified-add-location-type" name="location_type">
|
<input type="hidden" id="unified-add-location-type" name="location_type">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="unifiedAddLocationModalLabel">{% translate "Créer une localisation" %}</h5>
|
<h5 class="modal-title" id="unifiedAddLocationModalLabel">{% translate "Créer une localisation" %}</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||||
|
aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div id="unifiedAddLocationAlert" class="alert d-none" role="alert"></div>
|
<div id="unifiedAddLocationAlert" class="alert d-none" role="alert"></div>
|
||||||
|
|
@ -353,7 +477,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler"
|
||||||
|
%}</button>
|
||||||
<button type="submit" class="btn btn-success" id="unifiedAddLocationSubmit">
|
<button type="submit" class="btn btn-success" id="unifiedAddLocationSubmit">
|
||||||
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer la localisation" %}
|
<i class="bi bi-plus-circle me-1"></i>{% translate "Créer la localisation" %}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -383,12 +508,17 @@
|
||||||
{# Dropdown Tableaux spécifiques (générique selon les thématiques accessibles) #}
|
{# Dropdown Tableaux spécifiques (générique selon les thématiques accessibles) #}
|
||||||
{% if specific_tables %}
|
{% if specific_tables %}
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button class="btn btn-light btn-sm dropdown-toggle rounded-pill px-3 border shadow-sm d-inline-flex align-items-center"
|
<button
|
||||||
|
class="btn btn-light btn-sm dropdown-toggle rounded-pill px-3 border shadow-sm d-inline-flex align-items-center"
|
||||||
type="button" id="specificTablesDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
type="button" id="specificTablesDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
{% translate "Répertoires" %}
|
{% translate "Répertoires" %}
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-end shadow border-0 mt-1" aria-labelledby="specificTablesDropdown" style="min-width: 270px;">
|
<ul class="dropdown-menu dropdown-menu-end shadow border-0 mt-1" aria-labelledby="specificTablesDropdown"
|
||||||
<li><h6 class="dropdown-header text-uppercase small text-muted">{% translate "Répertoires spécifiques" %}</h6></li>
|
style="min-width: 270px;">
|
||||||
|
<li>
|
||||||
|
<h6 class="dropdown-header text-uppercase small text-muted">{% translate "Répertoires spécifiques"
|
||||||
|
%}</h6>
|
||||||
|
</li>
|
||||||
{% for table in specific_tables %}
|
{% for table in specific_tables %}
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item d-flex align-items-center gap-3 py-2" href="{{ table.url }}">
|
<a class="dropdown-item d-flex align-items-center gap-3 py-2" href="{{ table.url }}">
|
||||||
|
|
@ -407,13 +537,16 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="btn-group" role="group" aria-label="{% translate 'Sélection de la vue' %}">
|
<div class="btn-group" role="group" aria-label="{% translate 'Sélection de la vue' %}">
|
||||||
<button id="layout-btn-table" class="btn btn-light" type="button" title="{% translate 'Vue tableau uniquement' %}">
|
<button id="layout-btn-table" class="btn btn-light" type="button"
|
||||||
|
title="{% translate 'Vue tableau uniquement' %}">
|
||||||
<i class="bi bi-table"></i>
|
<i class="bi bi-table"></i>
|
||||||
</button>
|
</button>
|
||||||
<button id="layout-btn-both" class="btn btn-light text-primary" type="button" title="{% translate 'Vue partagée' %}">
|
<button id="layout-btn-both" class="btn btn-light text-primary" type="button"
|
||||||
|
title="{% translate 'Vue partagée' %}">
|
||||||
<i class="bi bi-layout-split"></i>
|
<i class="bi bi-layout-split"></i>
|
||||||
</button>
|
</button>
|
||||||
<button id="layout-btn-map" class="btn btn-light" type="button" title="{% translate 'Vue carte uniquement' %}">
|
<button id="layout-btn-map" class="btn btn-light" type="button"
|
||||||
|
title="{% translate 'Vue carte uniquement' %}">
|
||||||
<i class="bi bi-globe-europe-africa"></i>
|
<i class="bi bi-globe-europe-africa"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -427,24 +560,27 @@
|
||||||
<input type="text" id="assets-search-input" class="form-control form-control-sm"
|
<input type="text" id="assets-search-input" class="form-control form-control-sm"
|
||||||
style="width:100%; border-radius:20px 0 0 20px; border-color:#dee2e6; padding-right:1.6rem;"
|
style="width:100%; border-radius:20px 0 0 20px; border-color:#dee2e6; padding-right:1.6rem;"
|
||||||
placeholder="{% translate 'Code, nom, type…' %}">
|
placeholder="{% translate 'Code, nom, type…' %}">
|
||||||
<button type="button" id="assets-search-clear"
|
<button type="button" id="assets-search-clear" style="position:absolute; right:4px; top:50%; transform:translateY(-50%);
|
||||||
style="position:absolute; right:4px; top:50%; transform:translateY(-50%);
|
|
||||||
background:none; border:none; padding:0 2px; line-height:1;
|
background:none; border:none; padding:0 2px; line-height:1;
|
||||||
color:#adb5bd; cursor:pointer; visibility:hidden;"
|
color:#adb5bd; cursor:pointer; visibility:hidden;" title="{% translate 'Effacer' %}">
|
||||||
title="{% translate 'Effacer' %}">
|
|
||||||
<i class="bi bi-x-lg" style="font-size:0.7rem;"></i>
|
<i class="bi bi-x-lg" style="font-size:0.7rem;"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="input-group-text bg-white px-1" style="border-left:0; border-right:0; border-color:#dee2e6; flex-shrink:0;">
|
<span class="input-group-text bg-white px-1"
|
||||||
|
style="border-left:0; border-right:0; border-color:#dee2e6; flex-shrink:0;">
|
||||||
<div class="btn-group btn-group-sm" role="group">
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
<input type="radio" class="btn-check" name="assets-search-mode" id="assets-search-mode-and" value="and" checked>
|
<input type="radio" class="btn-check" name="assets-search-mode" id="assets-search-mode-and"
|
||||||
|
value="and" checked>
|
||||||
<label class="btn btn-outline-secondary py-0 px-2" for="assets-search-mode-and"
|
<label class="btn btn-outline-secondary py-0 px-2" for="assets-search-mode-and"
|
||||||
data-bs-toggle="tooltip" data-bs-placement="top"
|
data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
title="{% translate 'Tous les mots recherchés doivent être présents' %}">{% translate "ET" %}</label>
|
title="{% translate 'Tous les mots recherchés doivent être présents' %}">{% translate "ET"
|
||||||
<input type="radio" class="btn-check" name="assets-search-mode" id="assets-search-mode-or" value="or">
|
%}</label>
|
||||||
|
<input type="radio" class="btn-check" name="assets-search-mode" id="assets-search-mode-or"
|
||||||
|
value="or">
|
||||||
<label class="btn btn-outline-secondary py-0 px-2" for="assets-search-mode-or"
|
<label class="btn btn-outline-secondary py-0 px-2" for="assets-search-mode-or"
|
||||||
data-bs-toggle="tooltip" data-bs-placement="top"
|
data-bs-toggle="tooltip" data-bs-placement="top"
|
||||||
title="{% translate 'Au moins un des mots recherchés doit être présent' %}">{% translate "OU" %}</label>
|
title="{% translate 'Au moins un des mots recherchés doit être présent' %}">{% translate "OU"
|
||||||
|
%}</label>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<button class="btn btn-sm px-3" type="button" id="assets-search-btn"
|
<button class="btn btn-sm px-3" type="button" id="assets-search-btn"
|
||||||
|
|
@ -474,11 +610,11 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="my-1 ms-1">
|
<div class="my-1 ms-1">
|
||||||
<button class="btn btn-light position-relative" type="button"
|
<button class="btn btn-light position-relative" type="button" data-bs-toggle="modal"
|
||||||
data-bs-toggle="modal" data-bs-target="#filterModal"
|
data-bs-target="#filterModal" title="{% translate 'Filtres' %}">
|
||||||
title="{% translate 'Filtres' %}">
|
|
||||||
<i class="bi bi-funnel"></i> {% translate "Filtres" %}
|
<i class="bi bi-funnel"></i> {% translate "Filtres" %}
|
||||||
<span id="filter-badge" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-primary d-none">
|
<span id="filter-badge"
|
||||||
|
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-primary d-none">
|
||||||
<span id="filter-count">0</span>
|
<span id="filter-count">0</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -487,25 +623,31 @@
|
||||||
|
|
||||||
{# Tab content #}
|
{# Tab content #}
|
||||||
<div class="tab-content d-flex flex-column" style="flex: 1; min-height: 0;">
|
<div class="tab-content d-flex flex-column" style="flex: 1; min-height: 0;">
|
||||||
<div class="tab-pane fade show active d-flex flex-column" style="flex: 1; min-height: 0; padding-top: 0.5rem;">
|
<div class="tab-pane fade show active d-flex flex-column"
|
||||||
|
style="flex: 1; min-height: 0; padding-top: 0.5rem;">
|
||||||
|
|
||||||
{# Selection toolbar #}
|
{# Selection toolbar #}
|
||||||
<div class="d-flex gap-2 flex-wrap align-items-center mb-1">
|
<div class="d-flex gap-2 flex-wrap align-items-center mb-1">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="unified-select-all">{% translate "Tout sélectionner" %}</button>
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="unified-select-all">{%
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="unified-deselect-all">{% translate "Tout désélectionner" %}</button>
|
translate "Tout sélectionner" %}</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="unified-deselect-all">{%
|
||||||
|
translate "Tout désélectionner" %}</button>
|
||||||
{% if preventive_draft_id %}
|
{% if preventive_draft_id %}
|
||||||
<button type="submit" class="btn btn-success btn-sm" form="preventive-select-form">{% translate "Valider la sélection" %}</button>
|
<button type="submit" class="btn btn-success btn-sm" form="preventive-select-form">{% translate
|
||||||
|
"Valider la sélection" %}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div id="unified-selection-status" class="text-muted small mb-0">0 {% translate "sélectionné(s)" %}</div>
|
<div id="unified-selection-status" class="text-muted small mb-0">0 {% translate "sélectionné(s)"
|
||||||
|
%}</div>
|
||||||
{% if not preventive_draft_id %}
|
{% if not preventive_draft_id %}
|
||||||
<div class="dropdown ms-auto" id="unified-bulk-action-dropdown">
|
<div class="dropdown ms-auto" id="unified-bulk-action-dropdown">
|
||||||
<button class="btn btn-light btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<button class="btn btn-light btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown"
|
||||||
|
aria-expanded="false">
|
||||||
{% translate "Action" %}
|
{% translate "Action" %}
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="#" id="unified-action-export"
|
<a class="dropdown-item" href="#" id="unified-action-export" data-bs-toggle="modal"
|
||||||
data-bs-toggle="modal" data-bs-target="#unifiedExportModal">
|
data-bs-target="#unifiedExportModal">
|
||||||
<i class="bi bi-download me-2"></i>{% translate "Exporter" %}
|
<i class="bi bi-download me-2"></i>{% translate "Exporter" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -513,7 +655,8 @@
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="#" id="unified-action-bulk-status"
|
<a class="dropdown-item" href="#" id="unified-action-bulk-status"
|
||||||
data-bs-toggle="modal" data-bs-target="#bulkStatusModal">
|
data-bs-toggle="modal" data-bs-target="#bulkStatusModal">
|
||||||
<i class="bi bi-pencil-square me-2"></i>{% translate "Modifier le statut en masse" %}
|
<i class="bi bi-pencil-square me-2"></i>{% translate "Modifier le statut en
|
||||||
|
masse" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
@ -521,7 +664,8 @@
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="#" id="unified-action-bulk-validation-status"
|
<a class="dropdown-item" href="#" id="unified-action-bulk-validation-status"
|
||||||
data-bs-toggle="modal" data-bs-target="#bulkValidationStatusModal">
|
data-bs-toggle="modal" data-bs-target="#bulkValidationStatusModal">
|
||||||
<i class="bi bi-shield-check me-2"></i>{% translate "Modifier le statut de validation en masse" %}
|
<i class="bi bi-shield-check me-2"></i>{% translate "Modifier le statut de
|
||||||
|
validation en masse" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
@ -534,7 +678,8 @@
|
||||||
<div style="position: relative;">
|
<div style="position: relative;">
|
||||||
|
|
||||||
{# Spinner overlay — shown on top of existing table content during loading #}
|
{# Spinner overlay — shown on top of existing table content during loading #}
|
||||||
<div id="unified-spinner" style="display:none; position:absolute; inset:0; z-index:10; background:rgba(255,255,255,0.75); justify-content:center; align-items:flex-start; padding-top:2rem;">
|
<div id="unified-spinner"
|
||||||
|
style="display:none; position:absolute; inset:0; z-index:10; background:rgba(255,255,255,0.75); justify-content:center; align-items:flex-start; padding-top:2rem;">
|
||||||
<div class="spinner-border text-primary" role="status">
|
<div class="spinner-border text-primary" role="status">
|
||||||
<span class="visually-hidden">{% translate "Loading..." %}</span>
|
<span class="visually-hidden">{% translate "Loading..." %}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -543,16 +688,13 @@
|
||||||
{# Empty state #}
|
{# Empty state #}
|
||||||
<div id="unified-empty-state" class="text-center py-5">
|
<div id="unified-empty-state" class="text-center py-5">
|
||||||
<i class="bi bi-layers fs-1 text-muted"></i>
|
<i class="bi bi-layers fs-1 text-muted"></i>
|
||||||
<p class="mt-2">{% translate "Sélectionnez une ou plusieurs thématiques dans les filtres, saisissez une recherche ou zoomez sur la carte." %}</p>
|
<p class="mt-2">{% translate "Sélectionnez une ou plusieurs thématiques dans les filtres,
|
||||||
|
saisissez une recherche ou zoomez sur la carte." %}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Table #}
|
{# Table #}
|
||||||
<table id="unified-table"
|
<table id="unified-table" class="table table-hover table-sm" data-pagination="true"
|
||||||
class="table table-hover table-sm"
|
data-page-size="100" data-click-to-select="true" data-show-columns="true"
|
||||||
data-pagination="true"
|
|
||||||
data-page-size="100"
|
|
||||||
data-click-to-select="true"
|
|
||||||
data-show-columns="true"
|
|
||||||
data-search="false">
|
data-search="false">
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
@ -563,7 +705,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# ─── Map column ──────────────────────────────────────────────────── #}
|
{# ─── Map column ──────────────────────────────────────────────────── #}
|
||||||
<div id="col-map" class="col-md-6" style="position: relative; margin-top: 44px;">
|
<div id="col-map" class="col-md-6" style="position: relative; margin-top: 50px;">
|
||||||
<div id="info-panel">
|
<div id="info-panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<button id="info-panel-back" class="btn btn-sm btn-outline-secondary me-2" style="display:none;">
|
<button id="info-panel-back" class="btn btn-sm btn-outline-secondary me-2" style="display:none;">
|
||||||
|
|
@ -576,8 +718,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="map" style="position: relative; height: calc(100vh - 200px);">
|
<div id="map" style="position: relative; height: calc(100vh - 200px);">
|
||||||
<div id="assets-hint" class="small fst-italic position-absolute start-50 translate-middle-x bg-white px-3 py-1 rounded-pill shadow-sm border" style="top: 10px; z-index: 5; visibility: hidden; color: #0d6efd; white-space: nowrap; pointer-events: none;">
|
<div id="assets-hint"
|
||||||
<i class="bi bi-info-circle me-1"></i>{% translate "Choisissez une catégorie ou zoomez sur la carte pour voir les assets." %}
|
class="small fst-italic position-absolute start-50 translate-middle-x bg-white px-3 py-1 rounded-pill shadow-sm border"
|
||||||
|
style="top: 10px; z-index: 5; visibility: hidden; color: #0d6efd; white-space: nowrap; pointer-events: none;">
|
||||||
|
<i class="bi bi-info-circle me-1"></i>{% translate "Choisissez une catégorie ou zoomez sur la carte
|
||||||
|
pour voir les assets." %}
|
||||||
</div>
|
</div>
|
||||||
<div id="totalsOverlay" class="totals-overlay">
|
<div id="totalsOverlay" class="totals-overlay">
|
||||||
<div class="totals-toolbar">
|
<div class="totals-toolbar">
|
||||||
|
|
@ -590,35 +735,43 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button id="totals_button" class="btn btn-light mt-2 mb-1" type="button">{% translate "Totaux" %}</button>
|
<button id="totals_button" class="btn btn-light mt-2 mb-1" type="button">{% translate "Totaux"
|
||||||
|
%}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if not preventive_draft_id %}
|
{% if not preventive_draft_id %}
|
||||||
<div class="modal fade" id="unifiedExportModal" tabindex="-1" aria-labelledby="unifiedExportModalLabel" aria-hidden="true">
|
<div class="modal fade" id="unifiedExportModal" tabindex="-1" aria-labelledby="unifiedExportModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="unifiedExportModalLabel">{% translate "Exporter les assets sélectionnés" %}</h5>
|
<h5 class="modal-title" id="unifiedExportModalLabel">{% translate "Exporter les assets sélectionnés" %}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||||
|
aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p class="text-muted small">{% translate "Choisissez le format d'export :" %}</p>
|
<p class="text-muted small">{% translate "Choisissez le format d'export :" %}</p>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="unified-export-format" id="unified-export-format-csv" value="csv" checked>
|
<input class="form-check-input" type="radio" name="unified-export-format"
|
||||||
|
id="unified-export-format-csv" value="csv" checked>
|
||||||
<label class="form-check-label" for="unified-export-format-csv">CSV</label>
|
<label class="form-check-label" for="unified-export-format-csv">CSV</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="unified-export-format" id="unified-export-format-xlsx" value="xlsx">
|
<input class="form-check-input" type="radio" name="unified-export-format"
|
||||||
|
id="unified-export-format-xlsx" value="xlsx">
|
||||||
<label class="form-check-label" for="unified-export-format-xlsx">Excel (XLSX)</label>
|
<label class="form-check-label" for="unified-export-format-xlsx">Excel (XLSX)</label>
|
||||||
</div>
|
</div>
|
||||||
<div id="unified-export-error" class="alert alert-danger d-none mt-3" role="alert"></div>
|
<div id="unified-export-error" class="alert alert-danger d-none mt-3" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler"
|
||||||
<button type="button" class="btn btn-primary" id="unified-confirm-export-btn">{% translate "Exporter" %}</button>
|
%}</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="unified-confirm-export-btn">{% translate "Exporter"
|
||||||
|
%}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -646,8 +799,10 @@
|
||||||
<div id="bulk-status-error" class="alert alert-danger d-none" role="alert"></div>
|
<div id="bulk-status-error" class="alert alert-danger d-none" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler"
|
||||||
<button type="button" class="btn btn-primary" id="bulk-status-confirm-btn">{% translate "Enregistrer" %}</button>
|
%}</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="bulk-status-confirm-btn">{% translate "Enregistrer"
|
||||||
|
%}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -656,16 +811,19 @@
|
||||||
|
|
||||||
{# ─── Modal bulk validation status ──────────────────────────────────────── #}
|
{# ─── Modal bulk validation status ──────────────────────────────────────── #}
|
||||||
{% if has_bulk_edit_validation_status_permission %}
|
{% if has_bulk_edit_validation_status_permission %}
|
||||||
<div class="modal fade" id="bulkValidationStatusModal" tabindex="-1" aria-labelledby="bulkValidationStatusModalLabel" aria-hidden="true">
|
<div class="modal fade" id="bulkValidationStatusModal" tabindex="-1" aria-labelledby="bulkValidationStatusModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="bulkValidationStatusModalLabel">{% translate "Modifier le statut de validation en masse" %}</h5>
|
<h5 class="modal-title" id="bulkValidationStatusModalLabel">{% translate "Modifier le statut de
|
||||||
|
validation en masse" %}</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="bulk-validation-status-select" class="form-label">{% translate "Nouveau statut de validation" %}</label>
|
<label for="bulk-validation-status-select" class="form-label">{% translate "Nouveau statut de
|
||||||
|
validation" %}</label>
|
||||||
<select class="form-select" id="bulk-validation-status-select">
|
<select class="form-select" id="bulk-validation-status-select">
|
||||||
<option value="">-</option>
|
<option value="">-</option>
|
||||||
{% for value, label in asset_validation_status_choices %}
|
{% for value, label in asset_validation_status_choices %}
|
||||||
|
|
@ -676,8 +834,10 @@
|
||||||
<div id="bulk-validation-status-error" class="alert alert-danger d-none" role="alert"></div>
|
<div id="bulk-validation-status-error" class="alert alert-danger d-none" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler"
|
||||||
<button type="button" class="btn btn-primary" id="bulk-validation-status-confirm-btn">{% translate "Enregistrer" %}</button>
|
%}</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="bulk-validation-status-confirm-btn">{% translate
|
||||||
|
"Enregistrer" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -699,32 +859,32 @@
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script src="{% static 'common/mapbox-gl-draw.js' %}"></script>
|
<script src="{% static 'common/mapbox-gl-draw.js' %}"></script>
|
||||||
<script src="{% static 'common/layer-switcher-control.js' %}"></script>
|
<script src="{% static 'common/layer-switcher-control.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
const preventive_draft_id = "{{ preventive_draft_id|default:'' }}";
|
const preventive_draft_id = "{{ preventive_draft_id|default:'' }}";
|
||||||
var selected_locations_set = new Set({{ selected_locations_ids|safe }});
|
var selected_locations_set = new Set({{ selected_locations_ids| safe }});
|
||||||
const initial_selected_assets = {{ selected_assets_json|safe }};
|
const initial_selected_assets = {{ selected_assets_json| safe }};
|
||||||
var selected_assets_set = new Set();
|
var selected_assets_set = new Set();
|
||||||
const preventive_element_type = "{{ preventive_element_type|default:'' }}";
|
const preventive_element_type = "{{ preventive_element_type|default:'' }}";
|
||||||
const INITIAL_ASSET_LAYOUT = '{{ request.user.config.assets_list_layout|default:"both" }}';
|
const INITIAL_ASSET_LAYOUT = '{{ request.user.config.assets_list_layout|default:"both" }}';
|
||||||
|
|
||||||
const THEMATIC_CONFIG = {{ thematic_config_json|safe }};
|
const THEMATIC_CONFIG = {{ thematic_config_json| safe }};
|
||||||
const CONDITIONAL_FILTER_CONFIG = {{ conditional_filter_config_json|safe }};
|
const CONDITIONAL_FILTER_CONFIG = {{ conditional_filter_config_json| safe }};
|
||||||
const THEMATIC_CATEGORIES = {{ thematic_categories_json|safe }};
|
const THEMATIC_CATEGORIES = {{ thematic_categories_json| safe }};
|
||||||
const ADD_MODAL_CONFIG = {{ add_modal_config_json|safe }};
|
const ADD_MODAL_CONFIG = {{ add_modal_config_json| safe }};
|
||||||
const SELECTED_THEMATICS = {{ selected_thematics|safe }};
|
const SELECTED_THEMATICS = {{ selected_thematics| safe }};
|
||||||
const HAS_URL_THEMATICS = {% if has_url_thematics %}true{% else %}false{% endif %};
|
const HAS_URL_THEMATICS = {% if has_url_thematics %}true{% else %} false{% endif %};
|
||||||
const SELECTED_CATEGORIES = {{ selected_categories_json|safe }};
|
const SELECTED_CATEGORIES = {{ selected_categories_json| safe }};
|
||||||
const PREVENTIVE_DRAFT_ID = "{{ preventive_draft_id|default:'' }}";
|
const PREVENTIVE_DRAFT_ID = "{{ preventive_draft_id|default:'' }}";
|
||||||
const LOCKED_THEMATIC_CODE = "{{ locked_thematic_code|default:'' }}";
|
const LOCKED_THEMATIC_CODE = "{{ locked_thematic_code|default:'' }}";
|
||||||
const PREVENTIVE_ELEMENT_TYPE = "{{ preventive_element_type|default:'' }}";
|
const PREVENTIVE_ELEMENT_TYPE = "{{ preventive_element_type|default:'' }}";
|
||||||
const SELECTED_ASSETS = {{ selected_assets_json|safe }};
|
const SELECTED_ASSETS = {{ selected_assets_json| safe }};
|
||||||
const SELECTED_LOCATION_IDS = {{ selected_locations_ids|safe }};
|
const SELECTED_LOCATION_IDS = {{ selected_locations_ids| safe }};
|
||||||
const LINK_ASSETS_URL = "{{ link_assets_url|default:'' }}";
|
const LINK_ASSETS_URL = "{{ link_assets_url|default:'' }}";
|
||||||
const AUTOCOMPLETE_STREET_URL = "{% url 'common:autocomplete_street' %}";
|
const AUTOCOMPLETE_STREET_URL = "{% url 'common:autocomplete_street' %}";
|
||||||
const ASSET_MODELS_BY_CATEGORY_URL_TEMPLATE = "{% url 'assets:get_asset_models' 'THEMATIC_CODE' 0 %}";
|
const ASSET_MODELS_BY_CATEGORY_URL_TEMPLATE = "{% url 'assets:get_asset_models' 'THEMATIC_CODE' 0 %}";
|
||||||
const ASSETS_INDEX_PREFS = {{ assets_index_prefs_json|safe }};
|
const ASSETS_INDEX_PREFS = {{ assets_index_prefs_json| safe }};
|
||||||
const DEFAULT_THEMATIC_CODE = "{{ default_thematic_code|default:'' }}";
|
const DEFAULT_THEMATIC_CODE = "{{ default_thematic_code|default:'' }}";
|
||||||
const SAVE_ASSETS_PREFS_URL = "{% url 'common:save_assets_index_preferences' %}";
|
const SAVE_ASSETS_PREFS_URL = "{% url 'common:save_assets_index_preferences' %}";
|
||||||
const exportAssetsUrl = "{% url 'assets:export_assets' %}";
|
const exportAssetsUrl = "{% url 'assets:export_assets' %}";
|
||||||
|
|
@ -746,11 +906,11 @@
|
||||||
artworkmonument: "{% static 'assets/artwork_statue_icon.svg' %}?v=20260521a",
|
artworkmonument: "{% static 'assets/artwork_statue_icon.svg' %}?v=20260521a",
|
||||||
// publiclighting (poteaux, luminaires) uses a dedicated lamp-post SVG
|
// publiclighting (poteaux, luminaires) uses a dedicated lamp-post SVG
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
{% include "assets/includes/panel_rendering_functions.html" %}
|
{% include "assets/includes/panel_rendering_functions.html" %}
|
||||||
<script src="{% static 'common/base_script.js' %}"></script>
|
<script src="{% static 'common/base_script.js' %}"></script>
|
||||||
<script src="{% static 'common/base_map.js' %}"></script>
|
<script src="{% static 'common/base_map.js' %}"></script>
|
||||||
<script src="{% static 'assets/sign_panels_shared.js' %}?v=20260703c"></script>
|
<script src="{% static 'assets/sign_panels_shared.js' %}?v=20260703c"></script>
|
||||||
<script src="{% static 'assets/unified_map_layers.js' %}?v=20260726_pb"></script>
|
<script src="{% static 'assets/unified_map_layers.js' %}?v=20260726_pb"></script>
|
||||||
<script src="{% static 'assets/unified_index.js' %}?v=20260726_pb"></script>
|
<script src="{% static 'assets/unified_index.js' %}?v=20260726_pb"></script>
|
||||||
{% endblock script %}
|
{% endblock script %}
|
||||||
Loading…
Reference in a new issue