refactor: improve inspection document UI with file support, lazy loading, and translation fixes.
This commit is contained in:
parent
1c7e369fe3
commit
d9f1970ca6
11 changed files with 126 additions and 15 deletions
Binary file not shown.
|
|
@ -3658,8 +3658,8 @@ msgid "Actions"
|
|||
msgstr "Action"
|
||||
|
||||
#: assets/templates/assets/buildings/publicbuilding_detail.html:347
|
||||
msgid "Détail de l\\"
|
||||
msgstr "Detail of "
|
||||
msgid "Détail de l'asset"
|
||||
msgstr "Asset detail"
|
||||
|
||||
#: assets/templates/assets/buildings/publicbuilding_detail.html:354
|
||||
msgid "Aucun asset ou équipement technique enregistré."
|
||||
|
|
@ -4377,7 +4377,7 @@ msgstr "No inspection or verification recorded for this equipment."
|
|||
|
||||
#: assets/templates/assets/components/asset_inspections.html:89
|
||||
msgid "Détail de l'inspection"
|
||||
msgstr "Detail of "
|
||||
msgstr "Inspection detail"
|
||||
|
||||
#: assets/templates/assets/components/asset_inspections.html:98
|
||||
msgid "Inspection annulée"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -3663,8 +3663,8 @@ msgid "Actions"
|
|||
msgstr "Actions"
|
||||
|
||||
#: assets/templates/assets/buildings/publicbuilding_detail.html:347
|
||||
msgid "Détail de l\\"
|
||||
msgstr "Détail de l\\"
|
||||
msgid "Détail de l'asset"
|
||||
msgstr "Détail de l'asset"
|
||||
|
||||
#: assets/templates/assets/buildings/publicbuilding_detail.html:354
|
||||
msgid "Aucun asset ou équipement technique enregistré."
|
||||
|
|
@ -4383,7 +4383,7 @@ msgstr "Aucune inspection ni vérification enregistrée pour cet équipement."
|
|||
|
||||
#: assets/templates/assets/components/asset_inspections.html:89
|
||||
msgid "Détail de l'inspection"
|
||||
msgstr "Détail de l\\"
|
||||
msgstr "Détail de l'inspection"
|
||||
|
||||
#: assets/templates/assets/components/asset_inspections.html:98
|
||||
msgid "Inspection annulée"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -3657,8 +3657,8 @@ msgid "Actions"
|
|||
msgstr "Actie"
|
||||
|
||||
#: assets/templates/assets/buildings/publicbuilding_detail.html:347
|
||||
msgid "Détail de l\\"
|
||||
msgstr "Detail van "
|
||||
msgid "Détail de l'asset"
|
||||
msgstr "Assetdetail"
|
||||
|
||||
#: assets/templates/assets/buildings/publicbuilding_detail.html:354
|
||||
msgid "Aucun asset ou équipement technique enregistré."
|
||||
|
|
@ -4378,7 +4378,7 @@ msgstr "Geen wijzigingen geregistreerd voor dit asset."
|
|||
|
||||
#: assets/templates/assets/components/asset_inspections.html:89
|
||||
msgid "Détail de l'inspection"
|
||||
msgstr "Detail van "
|
||||
msgstr "Inspectiedetail"
|
||||
|
||||
#: assets/templates/assets/components/asset_inspections.html:98
|
||||
msgid "Inspection annulée"
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@
|
|||
</td>
|
||||
<td>{{ eq.next_control_date|date:"d/m/Y"|default:"-" }}</td>
|
||||
<td class="text-end pe-3">
|
||||
<a href="{{ eq.get_absolute_url }}" class="btn btn-sm btn-outline-info py-0 px-2 small text-nowrap" title="{% translate 'Détail de l\'asset' %}">
|
||||
<a href="{{ eq.get_absolute_url }}" class="btn btn-sm btn-outline-info py-0 px-2 small text-nowrap" title="{% translate \"Détail de l'asset\" %}">
|
||||
<i class="bi bi-eye me-1"></i>{% translate "Détail" %}
|
||||
</a>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -145,11 +145,18 @@
|
|||
{% if insp.documents.all %}
|
||||
<div>
|
||||
<label class="form-label text-muted small fw-semibold mb-2"><i class="bi bi-camera me-1"></i>{% translate "Photos & Documents joints" %} ({{ insp.documents.count }}):</label>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
{% for doc in insp.documents.all %}
|
||||
<a href="{{ doc.file_url }}" target="_blank" class="d-inline-block border rounded p-1 bg-light">
|
||||
<img data-src="{{ doc.file_url }}" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3C/svg%3E" loading="lazy" alt="Photo" class="rounded" style="width: 75px; height: 75px; object-fit: cover;">
|
||||
{% if doc.is_image %}
|
||||
<a href="{{ doc.file_url }}" target="_blank" class="d-inline-block border rounded p-1 bg-light" title="{{ doc.filename }}">
|
||||
<img data-src="{{ doc.file_url }}" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3C/svg%3E" loading="lazy" alt="{{ doc.filename }}" class="rounded" style="width: 75px; height: 75px; object-fit: cover;">
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ doc.file_url }}" target="_blank" class="btn btn-sm btn-outline-secondary d-inline-flex align-items-center gap-1" title="{{ doc.filename }}">
|
||||
<i class="bi bi-file-earmark-arrow-down text-primary"></i>
|
||||
<span class="text-truncate" style="max-width: 160px;">{{ doc.filename }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -260,7 +267,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
window.location.reload();
|
||||
} else {
|
||||
if (alertBox) {
|
||||
alertBox.textContent = data.error || "{% filter escapejs %}{% translate 'Erreur lors de l\'enregistrement.' %}{% endfilter %}";
|
||||
{% translate "Erreur lors de l'enregistrement." as err_save_msg %}
|
||||
alertBox.textContent = data.error || "{{ err_save_msg|escapejs }}";
|
||||
alertBox.classList.remove('d-none');
|
||||
}
|
||||
if (submitBtn) submitBtn.disabled = false;
|
||||
|
|
@ -279,6 +287,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
{% endif %}
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
function loadLazyModalImages(modal) {
|
||||
if (!modal || typeof modal.querySelectorAll !== 'function') return;
|
||||
modal.querySelectorAll('img[data-src]').forEach(function(img) {
|
||||
const dataSrc = img.getAttribute('data-src');
|
||||
if (dataSrc) {
|
||||
img.src = dataSrc;
|
||||
img.removeAttribute('data-src');
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener('show.bs.modal', function(e) {
|
||||
loadLazyModalImages(e.target);
|
||||
});
|
||||
document.addEventListener('shown.bs.modal', function(e) {
|
||||
loadLazyModalImages(e.target);
|
||||
});
|
||||
})();
|
||||
|
||||
window.handleToggleCancelAssetInspection = function(inspectionId, action) {
|
||||
const confirmMsg = action === 'cancel'
|
||||
? "{% filter escapejs %}{% translate 'Êtes-vous sûr de vouloir annuler cette inspection ?' %}{% endfilter %}"
|
||||
|
|
|
|||
|
|
@ -156,3 +156,48 @@ class ParkingSpotAndInspectionTest(TestCase):
|
|||
self.assertEqual(config["parking"]["assets_geojson_url"], reverse("assets:parking_assets_geojson"))
|
||||
self.assertEqual(config["parking"]["locations_geojson_url"], reverse("assets:parking_locations_geojson"))
|
||||
|
||||
def test_inspection_modal_title_and_thumbnails(self):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from inspections.models import InspectionDocument
|
||||
from django.utils.translation import activate
|
||||
|
||||
self.user_config.is_intern = True
|
||||
self.user_config.save()
|
||||
activate('fr')
|
||||
# Create an inspection on this parking spot
|
||||
inspection = ParkingSpotInspection.objects.create(
|
||||
asset=self.spot,
|
||||
inspector=self.user,
|
||||
inspection_date=timezone.now(),
|
||||
result_status="compliant",
|
||||
verified_standard_stand_count=3,
|
||||
notes="Inspection vélo conforme"
|
||||
)
|
||||
|
||||
photo = SimpleUploadedFile("arceau_velo.jpg", b"\xff\xd8\xff\xe0testimage", content_type="image/jpeg")
|
||||
doc_img = InspectionDocument.objects.create(inspection=inspection, file=photo)
|
||||
|
||||
url = reverse('assets:parking_assets_detail', kwargs={'asset_model': 'parkingspot', 'asset_id': self.spot.id})
|
||||
|
||||
# Test in French
|
||||
self.client.cookies['django_language'] = 'fr'
|
||||
response_fr = self.client.get(url)
|
||||
self.assertEqual(response_fr.status_code, 200)
|
||||
content_fr = response_fr.content.decode('utf-8')
|
||||
self.assertIn("Détail de l'inspection", content_fr)
|
||||
self.assertNotIn("Détail de \\", content_fr)
|
||||
|
||||
# Test in English
|
||||
self.client.cookies['django_language'] = 'en'
|
||||
response_en = self.client.get(url)
|
||||
self.assertEqual(response_en.status_code, 200)
|
||||
content_en = response_en.content.decode('utf-8')
|
||||
self.assertIn("Inspection detail", content_en)
|
||||
|
||||
# Check thumbnail rendering
|
||||
self.assertIn('data-src="', content_fr)
|
||||
self.assertIn(doc_img.filename, content_fr)
|
||||
self.assertIn('show.bs.modal', content_fr)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -372,6 +372,25 @@ if ('serviceWorker' in navigator) {
|
|||
});
|
||||
});
|
||||
|
||||
// Lazy loading des images dans les modales Bootstrap
|
||||
(function() {
|
||||
function loadLazyModalImages(modal) {
|
||||
if (!modal || typeof modal.querySelectorAll !== 'function') return;
|
||||
modal.querySelectorAll('img[data-src]').forEach(function(img) {
|
||||
const dataSrc = img.getAttribute('data-src');
|
||||
if (dataSrc) {
|
||||
img.src = dataSrc;
|
||||
img.removeAttribute('data-src');
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener('show.bs.modal', function(e) {
|
||||
loadLazyModalImages(e.target);
|
||||
});
|
||||
document.addEventListener('shown.bs.modal', function(e) {
|
||||
loadLazyModalImages(e.target);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- MapLibre GL 5.7.0 (local) -->
|
||||
|
|
|
|||
|
|
@ -546,6 +546,26 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Lazy loading des images dans les modales Bootstrap
|
||||
(function() {
|
||||
function loadLazyModalImages(modal) {
|
||||
if (!modal || typeof modal.querySelectorAll !== 'function') return;
|
||||
modal.querySelectorAll('img[data-src]').forEach(function(img) {
|
||||
const dataSrc = img.getAttribute('data-src');
|
||||
if (dataSrc) {
|
||||
img.src = dataSrc;
|
||||
img.removeAttribute('data-src');
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener('show.bs.modal', function(e) {
|
||||
loadLazyModalImages(e.target);
|
||||
});
|
||||
document.addEventListener('shown.bs.modal', function(e) {
|
||||
loadLazyModalImages(e.target);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script src="{% static 'common/help_panel.js' %}"></script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue