Skip to content

Commit cce7d2e

Browse files
authored
feat: tabs with filters (#876)
1 parent b342733 commit cce7d2e

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

src/unfold/sites.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from http import HTTPStatus
22
from typing import Any, Callable, Dict, List, Optional, Union
3+
from urllib.parse import parse_qs, urlparse
34

45
from django.contrib.admin import AdminSite
56
from django.contrib.auth import REDIRECT_FIELD_NAME
@@ -235,6 +236,7 @@ def password_change(
235236

236237
def get_sidebar_list(self, request: HttpRequest) -> List[Dict[str, Any]]:
237238
navigation = get_config(self.settings_name)["SIDEBAR"].get("navigation", [])
239+
tabs = get_config(self.settings_name)["TABS"]
238240
results = []
239241

240242
for group in navigation:
@@ -246,7 +248,8 @@ def get_sidebar_list(self, request: HttpRequest) -> List[Dict[str, Any]]:
246248
request, item.get("link_callback") or item["link"]
247249
)
248250

249-
for tab in get_config(self.settings_name)["TABS"]:
251+
# Checks if any tab item is active and then marks the sidebar link as active
252+
for tab in tabs:
250253
has_primary_link = False
251254
has_tab_link_active = False
252255

@@ -303,7 +306,7 @@ def get_tabs_list(self, request: HttpRequest) -> List[Dict[str, Any]]:
303306
item["link_callback"] = lazy(item["link"])(request)
304307

305308
item["active"] = self._get_is_active(
306-
request, item.get("link_callback") or item["link"]
309+
request, item.get("link_callback") or item["link"], True
307310
)
308311
allowed_items.append(item)
309312

@@ -392,13 +395,29 @@ def _process_colors(
392395

393396
return colors
394397

395-
def _get_is_active(self, request: HttpRequest, link: str) -> bool:
398+
def _get_is_active(
399+
self, request: HttpRequest, link: str, is_tab: bool = False
400+
) -> bool:
396401
if not isinstance(link, str):
397402
link = str(link)
398403

399-
if link in request.path and link != reverse_lazy(f"{self.name}:index"):
404+
index_path = reverse_lazy(f"{self.name}:index")
405+
link_path = urlparse(link).path
406+
407+
# Dashboard
408+
if link_path == request.path == index_path:
400409
return True
401-
elif link == request.path == reverse_lazy(f"{self.name}:index"):
410+
411+
if link_path in request.path and link_path != index_path:
412+
query_params = parse_qs(urlparse(link).query)
413+
request_params = parse_qs(request.GET.urlencode())
414+
415+
# In case of tabs, we need to check if the query params are the same
416+
if is_tab and not all(
417+
request_params.get(k) == v for k, v in query_params.items()
418+
):
419+
return False
420+
402421
return True
403422

404423
return False

src/unfold/templates/unfold/helpers/tab_list.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{% for item in tabs_list %}
99
{% if item.has_permission %}
1010
<li class="border-b last:border-b-0 md:border-b-0 md:mr-8 dark:border-gray-800">
11-
<a href="{% if item.link_callback %}{{ item.link_callback }}{% else %}{{ item.link }}{% endif %}" class="block px-3 py-2 md:py-4 md:px-0 dark:border-gray-800 {% if item.active %} border-b font-semibold -mb-px text-primary-600 hover:text-primary-600 dark:text-primary-500 dark:hover:text-primary-500 md:border-primary-500 dark:md:!border-primary-600{% else %}font-medium hover:text-gray-700 dark:hover:text-gray-200{% endif %}">
11+
<a href="{% if item.link_callback %}{{ item.link_callback }}{% else %}{{ item.link }}{% endif %}" class="block px-3 py-2 md:py-4 md:px-0 dark:border-gray-800 {% if item.active %} border-b font-semibold -mb-px text-primary-600 hover:text-primary-600 dark:text-primary-500 dark:hover:text-primary-500 md:border-primary-500 dark:md:!border-primary-600{% else %}font-medium hover:text-primary-600 dark:hover:text-primary-500{% endif %}">
1212
{{ item.title }}
1313
</a>
1414
</li>
@@ -20,7 +20,7 @@
2020
<a class="block cursor-pointer font-medium px-3 py-2 md:py-4 md:px-0"
2121
href="#general"
2222
x-on:click="activeTab = 'general'"
23-
x-bind:class="{'border-b border-gray-200 dark:border-gray-800 md:border-primary-500 dark:md:!border-primary-600 font-semibold -mb-px text-primary-600 dark:text-primary-500': activeTab == 'general', 'hover:text-gray-700 dark:hover:text-gray-200 dark:border-gray-800': activeTab != 'general'}">
23+
x-bind:class="{'border-b border-gray-200 dark:border-gray-800 md:border-primary-500 dark:md:!border-primary-600 font-semibold -mb-px text-primary-600 dark:text-primary-500': activeTab == 'general', 'hover:text-primary-600 dark:hover:text-primary-500 dark:border-gray-800': activeTab != 'general'}">
2424
{% trans "General" %}
2525
</a>
2626
</li>
@@ -30,7 +30,7 @@
3030
<a class="block cursor-pointer font-medium px-3 py-2 md:py-4 md:px-0"
3131
href="#{{ inline.opts.verbose_name|slugify }}"
3232
x-on:click="activeTab = '{{ inline.opts.verbose_name|slugify }}'"
33-
x-bind:class="{'border-b border-gray-200 dark:border-gray-800 md:border-primary-500 dark:md:!border-primary-600 font-semibold -mb-px text-primary-600 dark:text-primary-500': activeTab == '{{ inline.opts.verbose_name|slugify }}', 'hover:text-gray-700 dark:hover:text-gray-200 dark:border-gray-800': activeTab != '{{ inline.opts.verbose_name|slugify }}'}">
33+
x-bind:class="{'border-b border-gray-200 dark:border-gray-800 md:border-primary-500 dark:md:!border-primary-600 font-semibold -mb-px text-primary-600 dark:text-primary-500': activeTab == '{{ inline.opts.verbose_name|slugify }}', 'hover:text-primary-600 dark:hover:text-primary-500 dark:border-gray-800': activeTab != '{{ inline.opts.verbose_name|slugify }}'}">
3434
{% if inline.formset.max_num == 1 %}
3535
{{ inline.opts.verbose_name|capfirst }}
3636
{% else %}

0 commit comments

Comments
 (0)