feat: add dynamic active tab management and URL query param support for warehouse index view
This commit is contained in:
parent
20669d545b
commit
30051938d5
3 changed files with 55 additions and 13 deletions
|
|
@ -96,21 +96,21 @@
|
|||
<div class="col-md-6" id="col-left" style="max-height: calc(100vh - 100px); overflow: auto;">
|
||||
<ul class="nav nav-tabs" id="tablesTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="warehouses-table-tab" data-bs-toggle="tab" data-bs-target="#warehouses-table-content" type="button" role="tab" aria-controls="warehouses-table" aria-selected="true" style="color: black;"><i class="bi bi-buildings"></i> {% translate "Entrepôts" %}</button>
|
||||
<button class="nav-link {% if active_tab == 'warehouses' or not active_tab %}active{% endif %}" id="warehouses-table-tab" data-bs-toggle="tab" data-bs-target="#warehouses-table-content" type="button" role="tab" aria-controls="warehouses-table" aria-selected="{% if active_tab == 'warehouses' or not active_tab %}true{% else %}false{% endif %}" style="color: black;"><i class="bi bi-buildings"></i> {% translate "Entrepôts" %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="warehouse-locations-table-tab" data-bs-toggle="tab" data-bs-target="#warehouse-locations-table-content" type="button" role="tab" aria-controls="warehouse-locations-table" aria-selected="false" style="color: black;"><i class="bi bi-geo-alt"></i> {% translate "Emplacements" %}</button>
|
||||
<button class="nav-link {% if active_tab == 'warehouse-locations' %}active{% endif %}" id="warehouse-locations-table-tab" data-bs-toggle="tab" data-bs-target="#warehouse-locations-table-content" type="button" role="tab" aria-controls="warehouse-locations-table" aria-selected="{% if active_tab == 'warehouse-locations' %}true{% else %}false{% endif %}" style="color: black;"><i class="bi bi-geo-alt"></i> {% translate "Emplacements" %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="products-table-tab" data-bs-toggle="tab" data-bs-target="#products-table-content" type="button" role="tab" aria-controls="products-table" aria-selected="false" style="color: black;"><i class="bi bi-box-seam"></i> {% translate "Produits" %}</button>
|
||||
<button class="nav-link {% if active_tab == 'products' %}active{% endif %}" id="products-table-tab" data-bs-toggle="tab" data-bs-target="#products-table-content" type="button" role="tab" aria-controls="products-table" aria-selected="{% if active_tab == 'products' %}true{% else %}false{% endif %}" style="color: black;"><i class="bi bi-box-seam"></i> {% translate "Produits" %}</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="serialized-items-table-tab" data-bs-toggle="tab" data-bs-target="#serialized-items-table-content" type="button" role="tab" aria-controls="serialized-items-table" aria-selected="false" style="color: black;"><i class="bi bi-upc-scan"></i> {% translate "Articles tracés" %}</button>
|
||||
<button class="nav-link {% if active_tab == 'serialized-items' %}active{% endif %}" id="serialized-items-table-tab" data-bs-toggle="tab" data-bs-target="#serialized-items-table-content" type="button" role="tab" aria-controls="serialized-items-table" aria-selected="{% if active_tab == 'serialized-items' %}true{% else %}false{% endif %}" style="color: black;"><i class="bi bi-upc-scan"></i> {% translate "Articles tracés" %}</button>
|
||||
</li>
|
||||
{# Onglet Conception masqué (modèle conservé, non supprimé) #}
|
||||
</ul>
|
||||
<div class="tab-content my-2" id="tablesTabContent">
|
||||
<div class="tab-pane fade show active" id="warehouses-table-content" role="tabpanel" aria-labelledby="warehouses-table-tab">
|
||||
<div class="tab-pane fade {% if active_tab == 'warehouses' or not active_tab %}show active{% endif %}" id="warehouses-table-content" role="tabpanel" aria-labelledby="warehouses-table-tab">
|
||||
<!-- Spinner -->
|
||||
<div id="warehouses-spinner" class="table-spinner">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
|
|
@ -126,7 +126,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade show" id="warehouse-locations-table-content" role="tabpanel" aria-labelledby="warehouse-locations-table-tab">
|
||||
<div class="tab-pane fade {% if active_tab == 'warehouse-locations' %}show active{% endif %}" id="warehouse-locations-table-content" role="tabpanel" aria-labelledby="warehouse-locations-table-tab">
|
||||
<div id="warehouse-locations-table-container">
|
||||
<table id="warehouse-locations-table" class="table"
|
||||
data-height="500"
|
||||
|
|
@ -177,7 +177,7 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade show" id="products-table-content" role="tabpanel" aria-labelledby="products-table-tab">
|
||||
<div class="tab-pane fade {% if active_tab == 'products' %}show active{% endif %}" id="products-table-content" role="tabpanel" aria-labelledby="products-table-tab">
|
||||
<!-- Bouton ajout produit -->
|
||||
{% if can_manage_products %}
|
||||
<div class="d-flex justify-content-end mt-2 mb-1">
|
||||
|
|
@ -274,7 +274,7 @@
|
|||
{# <div class="tab-pane fade show" id="designs-table-content" ...> ... </div> #}
|
||||
|
||||
<!-- Onglet Articles tracés -->
|
||||
<div class="tab-pane fade" id="serialized-items-table-content" role="tabpanel" aria-labelledby="serialized-items-table-tab">
|
||||
<div class="tab-pane fade {% if active_tab == 'serialized-items' %}show active{% endif %}" id="serialized-items-table-content" role="tabpanel" aria-labelledby="serialized-items-table-tab">
|
||||
{% if can_manage_products %}
|
||||
<div class="d-flex justify-content-end mt-2 mb-1">
|
||||
<a href="{% url 'stock:serialized_item_create' %}" class="btn btn-sm btn-primary">
|
||||
|
|
@ -284,7 +284,7 @@
|
|||
{% endif %}
|
||||
|
||||
<form method="get" action="{% url 'stock:warehouses' %}" class="card mb-2 border-0 bg-light">
|
||||
<input type="hidden" name="tab" value="serialized-items-table">
|
||||
<input type="hidden" name="tab" value="serialized-items">
|
||||
<div class="card-body py-2 row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-semibold small mb-1">{% translate "Recherche" %}</label>
|
||||
|
|
@ -313,7 +313,7 @@
|
|||
<button type="submit" class="btn btn-sm btn-primary">
|
||||
<i class="bi bi-search"></i> {% translate "Filtrer" %}
|
||||
</button>
|
||||
<a href="{% url 'stock:warehouses' %}?tab=serialized-items-table" class="btn btn-sm btn-outline-secondary ms-1">
|
||||
<a href="{% url 'stock:warehouses' %}?tab=serialized-items" class="btn btn-sm btn-outline-secondary ms-1">
|
||||
<i class="bi bi-x-circle"></i> {% translate "Réinitialiser" %}
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -446,14 +446,27 @@
|
|||
document.querySelectorAll('#tablesTab button[data-bs-toggle="tab"]').forEach(function(btn) {
|
||||
btn.addEventListener('shown.bs.tab', function() {
|
||||
const tabName = btn.id.replace('-table-tab', '');
|
||||
history.replaceState(null, '', '?tab=' + tabName);
|
||||
const currentUrl = new URL(window.location.href);
|
||||
if (currentUrl.searchParams.get('tab') !== tabName) {
|
||||
if (tabName === 'serialized-items') {
|
||||
currentUrl.searchParams.set('tab', tabName);
|
||||
} else {
|
||||
currentUrl.search = '?tab=' + tabName;
|
||||
}
|
||||
history.replaceState(null, '', currentUrl.pathname + currentUrl.search);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Activer l'onglet indiqué par ?tab= au chargement de la page
|
||||
const tab = new URLSearchParams(window.location.search).get('tab');
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let tab = urlParams.get('tab');
|
||||
if (!tab && (urlParams.get('si_q') || urlParams.get('si_product') || urlParams.get('si_status'))) {
|
||||
tab = 'serialized-items';
|
||||
}
|
||||
if (tab) {
|
||||
const tabBtn = document.getElementById(tab + '-table-tab');
|
||||
const normalizedTab = tab.replace(/-table$/, '');
|
||||
const tabBtn = document.getElementById(normalizedTab + '-table-tab') || document.getElementById(tab + '-table-tab');
|
||||
if (tabBtn) {
|
||||
tabBtn.click();
|
||||
tabBtn.blur();
|
||||
|
|
|
|||
|
|
@ -1162,6 +1162,26 @@ class ProductLocationsTests(TestCase):
|
|||
self.assertContains(response, "SN-MOB-TEST")
|
||||
self.assertContains(response, "editItemMobileModal")
|
||||
|
||||
def test_warehouses_index_serialized_items_tab_active(self):
|
||||
response = self.client.get(reverse("stock:warehouses") + "?tab=serialized-items")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["active_tab"], "serialized-items")
|
||||
|
||||
def test_warehouses_index_serialized_items_table_legacy_tab_active(self):
|
||||
response = self.client.get(reverse("stock:warehouses") + "?tab=serialized-items-table")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["active_tab"], "serialized-items")
|
||||
|
||||
def test_warehouses_index_filter_by_query_activates_serialized_items_tab(self):
|
||||
response = self.client.get(reverse("stock:warehouses") + "?si_q=makita")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["active_tab"], "serialized-items")
|
||||
|
||||
def test_warehouses_index_default_tab_is_warehouses(self):
|
||||
response = self.client.get(reverse("stock:warehouses"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["active_tab"], "warehouses")
|
||||
|
||||
|
||||
class AssociateStockLocationsCommandTests(TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
|||
|
|
@ -100,6 +100,14 @@ def warehouses_index(request):
|
|||
si_query = request.GET.get("si_q", "").strip()
|
||||
si_product_id = request.GET.get("si_product", "").strip()
|
||||
si_status = request.GET.get("si_status", "").strip()
|
||||
tab_param = request.GET.get("tab", "").strip()
|
||||
|
||||
if tab_param in ("serialized-items", "serialized-items-table") or (not tab_param and (si_query or si_product_id or si_status)):
|
||||
active_tab = "serialized-items"
|
||||
elif tab_param in ("products", "warehouse-locations", "warehouses"):
|
||||
active_tab = tab_param
|
||||
else:
|
||||
active_tab = "warehouses"
|
||||
|
||||
serialized_items_qs = SerializedItem.objects.select_related(
|
||||
"product", "current_location__warehouse", "current_holder"
|
||||
|
|
@ -129,6 +137,7 @@ def warehouses_index(request):
|
|||
"si_product_id": si_product_id,
|
||||
"si_status": si_status,
|
||||
"si_status_choices": SerializedItem.STATUS_CHOICES,
|
||||
"active_tab": active_tab,
|
||||
}
|
||||
return render(request, "stock/warehouses_index.html", context)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue