feat: implement structures management module with index views, location geojson endpoints, and modal for adding assets
This commit is contained in:
parent
ff4042b333
commit
360db5aaad
5 changed files with 99 additions and 12 deletions
|
|
@ -20,6 +20,18 @@
|
|||
|
||||
const categoriesCache = {};
|
||||
|
||||
function populateCategorySelectIfEmpty(select, categories) {
|
||||
if (!select || select.options.length > 1 || !categories || categories.length === 0) {
|
||||
return;
|
||||
}
|
||||
categories.forEach(cat => {
|
||||
const option = document.createElement('option');
|
||||
option.value = cat.id;
|
||||
option.textContent = cat.name;
|
||||
select.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
function initializeForm(form, modalId) {
|
||||
const thematicCode = form.dataset.thematic;
|
||||
const categorySelect = form.querySelector('.asset-category-select');
|
||||
|
|
@ -31,17 +43,22 @@
|
|||
const submitBtn = form.querySelector(`#${modalId}Submit`);
|
||||
|
||||
// Fetch and cache categories for this thematic
|
||||
if (thematicCode && !categoriesCache[thematicCode]) {
|
||||
fetch(`/assets/${thematicCode}/categories/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.categories) {
|
||||
categoriesCache[thematicCode] = data.categories;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error prefetching categories:', error);
|
||||
});
|
||||
if (thematicCode) {
|
||||
if (categoriesCache[thematicCode]) {
|
||||
populateCategorySelectIfEmpty(categorySelect, categoriesCache[thematicCode]);
|
||||
} else {
|
||||
fetch(`/assets/${thematicCode}/categories/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.categories) {
|
||||
categoriesCache[thematicCode] = data.categories;
|
||||
populateCategorySelectIfEmpty(categorySelect, data.categories);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error prefetching categories:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function onCategoryChange() {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@
|
|||
{% if intervention_id %}
|
||||
<input type="hidden" name="intervention_id" value="{{ intervention_id }}">
|
||||
{% endif %}
|
||||
{% if location %}
|
||||
<input type="hidden" name="location_id" value="{{ location.id }}">
|
||||
{% endif %}
|
||||
{% if structure %}
|
||||
<input type="hidden" name="structure_id" value="{{ structure.id }}">
|
||||
{% endif %}
|
||||
<input type="hidden" name="thematic_code" value="{{ thematic_code }}">
|
||||
|
||||
<div class="modal-body">
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@
|
|||
|
||||
<!-- Add Asset Modal -->
|
||||
{% if can_create_assets %}
|
||||
{% include "assets/components/add_asset_modal.html" with modal_id="addAssetLocationModal" thematic_code="structures" location=location %}
|
||||
{% include "assets/components/add_asset_modal.html" with modal_id="addAssetLocationModal" thematic_code="structures" location=location categories=categories %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock content%}
|
||||
|
|
|
|||
|
|
@ -374,6 +374,65 @@ class CategoryAllowedModelTest(TestCase):
|
|||
self.assertFalse(accessory_model["is_model_required"])
|
||||
|
||||
|
||||
class StructuresLocationDetailAddAssetModalTest(TestCase):
|
||||
def setUp(self):
|
||||
from common.models import Role
|
||||
from assets.models.structures import Structure, StructureLocation
|
||||
from django.contrib.gis.geos import Point
|
||||
|
||||
self.user = User.objects.create_superuser(username="admin_struct", password="password123")
|
||||
self.config = UserConfig.objects.create(user=self.user, is_intern=True)
|
||||
admin_role, _ = Role.objects.get_or_create(name="admin")
|
||||
self.config.roles.add(admin_role)
|
||||
|
||||
self.thematic, _ = Thematic.objects.get_or_create(
|
||||
code="structures",
|
||||
defaults={"name_fr": "Ouvrages d'art", "name_nl": "Kunstwerken"}
|
||||
)
|
||||
UserThematics.objects.create(
|
||||
user_config=self.config,
|
||||
thematic=self.thematic,
|
||||
can_view_assets=True,
|
||||
can_edit_assets=True
|
||||
)
|
||||
|
||||
self.category, _ = AssetCategory.objects.get_or_create(
|
||||
code="TU_BAL_TEST",
|
||||
defaults={
|
||||
"name_fr": "Balisage Test",
|
||||
"name_nl": "Balisage Test NL",
|
||||
"thematic": self.thematic
|
||||
}
|
||||
)
|
||||
|
||||
from django.contrib.gis.geos import MultiPolygon, Polygon
|
||||
poly = Polygon(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)))
|
||||
mpoly = MultiPolygon(poly, srid=3812)
|
||||
|
||||
self.structure = Structure.objects.create(
|
||||
code="OA_TEST_01",
|
||||
name_fr="Pont Test",
|
||||
structure_type="bridge"
|
||||
)
|
||||
self.location = StructureLocation.objects.create(
|
||||
code="LOC_TEST_01",
|
||||
name_fr="Localisation Test",
|
||||
structure=self.structure,
|
||||
geom=mpoly
|
||||
)
|
||||
|
||||
def test_structures_location_detail_contains_categories(self):
|
||||
self.client.force_login(self.user)
|
||||
response = self.client.get(reverse("assets:structures_locations_detail", args=[self.location.id]))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("categories", response.context)
|
||||
categories_in_context = response.context["categories"]
|
||||
self.assertTrue(any(c.id == self.category.id for c in categories_in_context))
|
||||
self.assertContains(response, "Balisage Test")
|
||||
self.assertContains(response, f'name="location_id" value="{self.location.id}"')
|
||||
|
||||
|
||||
|
||||
from assets.views.trafficlights import parse_dxf_poles
|
||||
|
||||
@tag('slow', 'dxf')
|
||||
|
|
|
|||
|
|
@ -621,10 +621,15 @@ def structures_locations_detail(request, location_id):
|
|||
|
||||
geom = json.loads(location_geom_4326.geojson) if location_geom_4326 else None
|
||||
|
||||
# Récupérer les catégories d'assets pour la thématique "structures"
|
||||
categories = list(AssetCategory.objects.filter(thematic__code='structures'))
|
||||
categories.sort(key=lambda m: m.get_name().lower())
|
||||
|
||||
return render(request, "assets/structures_location_detail.html", {
|
||||
"location": location,
|
||||
"interventions": interventions, # toutes les interventions de l'arbre
|
||||
"assets": assets,
|
||||
"categories": categories,
|
||||
"main_documents": main_documents,
|
||||
"other_documents": other_docs,
|
||||
"add_document_form": StructureDocumentForm(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue