[UPDT] HORILLA VIEWS: get_item condition update
This commit is contained in:
@@ -327,9 +327,9 @@ class Reverse:
|
||||
return str(self.reverse)
|
||||
|
||||
|
||||
def getmodelattribute(value, attr: str):
|
||||
def getmodelattribute(value: models.Model, attr: str):
|
||||
"""
|
||||
Gets an attribute of a model dynamically from a string name, handling related fields.
|
||||
Gets an attribute of a model dynamically, handling related fields.
|
||||
"""
|
||||
result = value
|
||||
attrs = attr.split("__")
|
||||
|
||||
@@ -48,7 +48,7 @@ class HorillaListView(ListView):
|
||||
|
||||
export_file_name: str = None
|
||||
|
||||
template_name: str = "generic/horilla_list.html"
|
||||
template_name: str = "generic/horilla_list_table.html"
|
||||
context_object_name = "queryset"
|
||||
# column = [("Verbose Name","field_name","avatar_mapping")], opt: avatar_mapping
|
||||
columns: list = []
|
||||
@@ -97,6 +97,8 @@ class HorillaListView(ListView):
|
||||
bulk_update_fields: list = []
|
||||
bulk_template: str = "generic/bulk_form.html"
|
||||
|
||||
header_attrs: dict = {}
|
||||
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
if not self.view_id:
|
||||
self.view_id = get_short_uuid(4)
|
||||
@@ -246,6 +248,8 @@ class HorillaListView(ListView):
|
||||
context["options"] = self.options
|
||||
context["row_attrs"] = self.row_attrs
|
||||
|
||||
context["header_attrs"] = self.header_attrs
|
||||
|
||||
context["show_filter_tags"] = self.show_filter_tags
|
||||
context["bulk_select_option"] = self.bulk_select_option
|
||||
context["row_status_class"] = self.row_status_class
|
||||
@@ -329,7 +333,7 @@ class HorillaListView(ListView):
|
||||
|
||||
if request and self._saved_filters.get("field"):
|
||||
field = self._saved_filters.get("field")
|
||||
self.template_name = "generic/group_by.html"
|
||||
self.template_name = "generic/group_by_table.html"
|
||||
if isinstance(queryset, Page):
|
||||
queryset = self.filter_class(
|
||||
request.GET, queryset=queryset.object_list.model.objects.all()
|
||||
@@ -514,6 +518,8 @@ class HorillaDetailedView(DetailView):
|
||||
instance_ids = eval(str(self.request.GET.get(self.ids_key)))
|
||||
|
||||
pk = context["object"].pk
|
||||
if instance_ids:
|
||||
context["object"].ordered_ids = instance_ids
|
||||
context["instance"] = context["object"]
|
||||
|
||||
url = resolve(self.request.path)
|
||||
@@ -812,6 +818,8 @@ class HorillaFormView(FormView):
|
||||
super().__init__(**kwargs)
|
||||
request = getattr(_thread_locals, "request", None)
|
||||
self.request = request
|
||||
if not self.success_url:
|
||||
self.success_url = self.request.path
|
||||
update_initial_cache(request, CACHE, HorillaFormView)
|
||||
|
||||
if self.form_class:
|
||||
@@ -832,7 +840,7 @@ class HorillaFormView(FormView):
|
||||
response = super().post(request, *args, **kwargs)
|
||||
return response
|
||||
|
||||
def init_form(self, *args, data=None, files=None, instance=None, **kwargs):
|
||||
def init_form(self, *args, data={}, files={}, instance=None, **kwargs):
|
||||
"""
|
||||
method where first the form where initialized
|
||||
"""
|
||||
|
||||
399
horilla_views/templates/generic/group_by_table.html
Normal file
399
horilla_views/templates/generic/group_by_table.html
Normal file
@@ -0,0 +1,399 @@
|
||||
{% load static i18n generic_template_filters %}
|
||||
|
||||
<div id="{{view_id|safe}}">
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="bulkUpdateModal{{view_id|safe}}"
|
||||
role="dialog"
|
||||
aria-labelledby="bulkUpdateModal{{view_id|safe}}"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="oh-modal__dialog" id="bulkUpdateModalBody{{view_id|safe}}"></div>
|
||||
</div>
|
||||
{% include "generic/export_fields_modal.html" %}
|
||||
<script>
|
||||
if (!$(".HTV").length) {
|
||||
$("#reloadMessagesButton").click()
|
||||
}
|
||||
</script>
|
||||
{% if bulk_select_option and queryset|length %}
|
||||
{% include "generic/quick_actions.html" %}
|
||||
{% endif %}
|
||||
<button class="reload-record" id="{{view_id|safe}}Reload" hidden hx-get="{{request.path}}?{{request.GET.urlencode}}" hx-target="#{{view_id|safe}}" hx-swap="outerHTML">
|
||||
</button>
|
||||
{% if show_filter_tags %} {% include "generic/filter_tags.html" %} {% endif %}
|
||||
<div class="oh-card">
|
||||
{% if not groups.paginator.count %}
|
||||
<div class="oh-wrapper" align="center" style="margin-top: 7vh; margin-bottom:7vh;">
|
||||
<div align="center">
|
||||
<img src="{% static "images/ui/search.svg" %}" class="oh-404__image" alt="Page not found. 404.">
|
||||
<h1 class="oh-404__title">{% trans "No Records found" %}</h1>
|
||||
<p class="oh-404__subtitle">
|
||||
{% trans "No records found." %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for group in groups %}
|
||||
<div class="oh-accordion-meta">
|
||||
<div class="oh-accordion-meta__item">
|
||||
<div class="oh-accordion-meta__header"
|
||||
data-field="{{saved_filters.field}}"
|
||||
data-path="{{request.path}}"
|
||||
data-group="{{forloop.counter}}"
|
||||
data-open=false
|
||||
onclick="
|
||||
event.stopPropagation()
|
||||
$(this).parent().find('.oh-accordion-meta__body').toggleClass('d-none')
|
||||
"
|
||||
>
|
||||
<span class="oh-accordion-meta__title p-2">
|
||||
<span class="oh-accordion-meta__title pt-3 pb-3">
|
||||
<div class="oh-tabs__input-badge-container">
|
||||
<span
|
||||
class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round mr-1"
|
||||
title="{{group.list.paginator.count}} {% trans "Records" %}"
|
||||
>
|
||||
{{group.list.paginator.count}}
|
||||
</span>
|
||||
{{group.grouper|capfirst}}
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="oh-accordion-meta__body d-none">
|
||||
<div class="table-wrapper">
|
||||
<table class="fixed-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if bulk_select_option %}
|
||||
<th>
|
||||
<div class="centered-div" align="center">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="oh-input oh-input__checkbox bulk-list-table-row"
|
||||
onchange="
|
||||
$(this).closest('.fixed-table').find('.list-table-row').prop('checked',$(this).is(':checked')).change();
|
||||
$(document).ready(function () {
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
});
|
||||
"
|
||||
title="Select All"
|
||||
/>
|
||||
</div>
|
||||
</th>
|
||||
{% endif %}
|
||||
{% for cell in columns %}
|
||||
{% with cell_attr=header_attrs|get_item:cell.1 %}
|
||||
<th {% if cell.2 and not cell_attr %}style="width:220px!important;"{% endif %} {{cell_attr|safe}} id="{{view_id}}-{{ forloop.counter }}-{{cell.1}}-header">
|
||||
<div
|
||||
{% for sort_map in sortby_mapping %}
|
||||
{% if sort_map.0 == cell.0 %}
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&{{sortby_key}}={{sort_map.1}}&filter_applied=on"
|
||||
hx-target="#{{view_id}}"
|
||||
class="
|
||||
{% if request.sort_order == "asc" and request.sort_key == sort_map.1 %}
|
||||
arrow-up
|
||||
{% elif request.sort_order == "desc" and request.sort_key == sort_map.1 %}
|
||||
arrow-down
|
||||
{% else %}
|
||||
arrow-up-down
|
||||
{% endif %}
|
||||
"
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
>
|
||||
{{cell.0}}
|
||||
</div>
|
||||
</th>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% if options or option_method%}
|
||||
<th {{header_attrs.option|safe}}>
|
||||
{% trans "Options" %}
|
||||
</th>
|
||||
{% endif %}
|
||||
{% if actions or action_method %}
|
||||
<th class="lastTh" {{header_attrs.action|safe}}>
|
||||
{% trans "Actions" %}
|
||||
</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instance in group.list %}
|
||||
<tr
|
||||
data-instance-id="{{instance.id}}"
|
||||
{{row_attrs|format:instance|safe}}
|
||||
>
|
||||
{% if bulk_select_option %}
|
||||
<td class="p-0" onclick="event.stopPropagation()">
|
||||
<div class="{{row_status_class|format:instance|safe}} centered-div" align="center">
|
||||
<input
|
||||
type="checkbox"
|
||||
data-view-id="{{view_id|safe}}"
|
||||
class="oh-input oh-input__checkbox list-table-row"
|
||||
onchange="
|
||||
element = $(this)
|
||||
highlightRow(element);
|
||||
$(document).ready(function () {
|
||||
if (!element.is(':checked')) {
|
||||
removeId(element)
|
||||
}
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
});
|
||||
"
|
||||
title="{% trans "Select Row" %}"
|
||||
value = "{{instance.pk}}"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% for cell in columns %}
|
||||
{% with attribute=cell.1 index=forloop.counter %}
|
||||
<td>
|
||||
{% if not cell.2 %}
|
||||
{{instance|getattribute:attribute|selected_format:request.user.employee_get.employee_work_info.company_id|safe}}
|
||||
{% else %}
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{instance|getattribute:cell.2}}"
|
||||
class="oh-profile__image"
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">
|
||||
{{instance|getattribute:attribute}}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% if options or option_method %}
|
||||
<td onclick="event.stopPropagation()">
|
||||
{% if not option_method %}
|
||||
<div class="oh-btn-group">
|
||||
{% for option in options %}
|
||||
{% if option.accessibility|accessibility:instance %}
|
||||
<a
|
||||
href="#"
|
||||
title="{{option.option|safe}}"
|
||||
{{option.attrs|format:instance|safe}}
|
||||
>
|
||||
<ion-icon name="{{option.icon}}"></ion-icon>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %} {{instance|getattribute:option_method|safe}} {% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if actions or action_method %}
|
||||
<td class="lastTd" onclick="event.stopPropagation()">
|
||||
{% if not action_method %}
|
||||
<div class="oh-btn-group">
|
||||
{% for action in actions %}
|
||||
{% if action.accessibility|accessibility:instance %}
|
||||
<button
|
||||
href="#"
|
||||
title="{{action.action|safe}}"
|
||||
{{action.attrs|format:instance|safe}}
|
||||
>
|
||||
<ion-icon name="{{action.icon}}"></ion-icon>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %} {{instance|getattribute:action_method|safe}} {% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let thWidth = 0;
|
||||
const widths = [];
|
||||
|
||||
$('.lastTd').each(function () {
|
||||
widths.push(this.scrollWidth);
|
||||
$(this).css('overflow', 'hidden');
|
||||
});
|
||||
|
||||
widths.sort().reverse();
|
||||
|
||||
if (widths.length) {
|
||||
thWidth = widths[0];
|
||||
}
|
||||
|
||||
$('.lastTh').css("width", `${thWidth}px`);
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div class="oh-pagination">
|
||||
<span class="oh-pagination__page">
|
||||
{% trans "Page" %} {{ group.list.number }}
|
||||
{% trans "of" %} {{ group.list.paginator.num_pages }}.
|
||||
</span>
|
||||
<nav class="oh-pagination__nav">
|
||||
<div class="oh-pagination__input-container me-3">
|
||||
<span class="oh-pagination__label me-1"
|
||||
>{% trans "Page" %}</span
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
name="{{group.dynamic_name}}"
|
||||
class="oh-pagination__input"
|
||||
value="{{group.list.number}}"
|
||||
hx-get="{{search_url}}?{{request.GET.urlencode}}"
|
||||
hx-target="#{{view_id}}"
|
||||
min="1"
|
||||
/>
|
||||
<span class="oh-pagination__label"
|
||||
>{% trans "of" %}
|
||||
{{group.list.paginator.num_pages}}</span
|
||||
>
|
||||
</div>
|
||||
<ul class="oh-pagination__items">
|
||||
{% if group.list.has_previous %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#{{view_id}}"
|
||||
hx-get="{{search_url}}?{{request.GET.urlencode}}&{{group.dynamic_name}}=1"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "First" %}</a
|
||||
>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#{{view_id}}"
|
||||
hx-get="{{search_url}}?{{request.GET.urlencode}}&{{group.dynamic_name}}={{ group.list.previous_page_number }}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Previous" %}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %} {% if group.list.has_next %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#{{view_id}}"
|
||||
hx-get="{{search_url}}?{{request.GET.urlencode}}&{{group.dynamic_name}}={{ group.list.next_page_number }}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Next" %}</a
|
||||
>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#{{view_id}}"
|
||||
hx-get="{{search_url}}?{{request.GET.urlencode}}&{{group.dynamic_name}}={{ group.list.paginator.num_pages }}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Last" %}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if groups.paginator.count %}
|
||||
<div class="oh-pagination">
|
||||
<span
|
||||
class="oh-pagination__page"
|
||||
data-toggle="modal"
|
||||
data-target="#addEmployeeModal"
|
||||
>{% trans "Page" %} {{groups.number}} {% trans "of" %} {{groups.paginator.num_pages}}</span
|
||||
>
|
||||
|
||||
<nav class="oh-pagination__nav">
|
||||
<div class="oh-pagination__input-container me-3">
|
||||
<span class="oh-pagination__label me-1">{% trans "Page" %}</span>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
class="oh-pagination__input"
|
||||
value="{{groups.number}}"
|
||||
min="1"
|
||||
name="page"
|
||||
hx-get="{{search_url}}?{{request.GET.urlencode}}"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#{{view_id|safe}}"
|
||||
/>
|
||||
<span class="oh-pagination__label">{% trans "of" %} {{groups.paginator.num_pages}}</span>
|
||||
</div>
|
||||
|
||||
<ul class="oh-pagination__items">
|
||||
{% if groups.has_previous %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a hx-get="{{search_url}}?{{request.GET.urlencode}}&page=1" hx-swap="outerHTML" hx-target="#{{view_id|safe}}" class="oh-pagination__link">{% trans "First" %}</a>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a hx-get="{{search_url}}?{{request.GET.urlencode}}&page={{ groups.previous_page_number }}" hx-swap="outerHTML" hx-target="#{{view_id|safe}}" class="oh-pagination__link">{% trans "Previous" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if groups.has_next %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a hx-get="{{search_url}}?{{request.GET.urlencode}}&page={{ groups.next_page_number }}" hx-swap="outerHTML" hx-target="#{{view_id|safe}}" class="oh-pagination__link">{% trans "Next" %}</a>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a hx-get="{{search_url}}?{{request.GET.urlencode}}&page={{ groups.paginator.num_pages }}" hx-swap="outerHTML" hx-target="#{{view_id|safe}}" class="oh-pagination__link">{% trans "Last" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<script>
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
var tabId = $("#{{view_id}}").closest(".oh-tabs__content").attr("id")
|
||||
var badge = $(`#badge-${tabId}`)
|
||||
var count = "{{queryset.paginator.count}}"
|
||||
var label = badge.attr("data-badge-label") || ""
|
||||
var title = count + " " + label
|
||||
badge.html(count)
|
||||
badge.attr("title",title)
|
||||
</script>
|
||||
{% if bulk_select_option %}
|
||||
<script>
|
||||
selectSelected("#{{view_id|safe}}",'{{selected_instances_key_id}}')
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
$(".oh-accordion-meta__header").click(function (e) {
|
||||
var open = $(this).attr("data-open");
|
||||
open = JSON.parse(open)
|
||||
if (!$(this).parent().parent().find(".oh-accordion-meta__body.d-none").length && !$(this).find(".oh-accordion-meta__header--show").length) {
|
||||
$(this).removeClass("oh-accordion-meta__header--show");
|
||||
}else{
|
||||
$(this).addClass("oh-accordion-meta__header--show");
|
||||
}
|
||||
$(this).attr("data-open", !open);
|
||||
var field = $(this).attr("data-field");
|
||||
var groupIndex = $(this).attr("data-group");
|
||||
var target = `[data-group="${groupIndex}"][data-field="${field}"][data-path="{{request.path}}"][data-open="${open}"]`;
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
type: "get",
|
||||
url: "{% url 'cbv-active-group' %}",
|
||||
data: {
|
||||
"path":"{{request.path}}",
|
||||
"target":target,
|
||||
"field":field,
|
||||
},
|
||||
success: function (response) {
|
||||
}
|
||||
});
|
||||
});
|
||||
{% if active_target %}
|
||||
$("#{{view_id|safe}}").find(`{{active_target|safe}}`).click();
|
||||
{% endif %}
|
||||
</script>
|
||||
</div>
|
||||
@@ -94,12 +94,16 @@
|
||||
{% if actions and not action_method %}
|
||||
<div class="oh-btn-group" style="width: 100%">
|
||||
{% for action in actions %}
|
||||
<button {{action.attrs|format:object|safe}}>
|
||||
<a {{action.attrs|format:object|safe}}>
|
||||
<ion-icon name="{{action.icon}}"></ion-icon>
|
||||
{{action.action}}
|
||||
</button>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %} {{object|getattribute:action_method|safe}} {% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$("#reloadMessagesButton").click();
|
||||
</script>
|
||||
|
||||
358
horilla_views/templates/generic/horilla_list_table.html
Normal file
358
horilla_views/templates/generic/horilla_list_table.html
Normal file
@@ -0,0 +1,358 @@
|
||||
{% load static i18n generic_template_filters %}
|
||||
<div id="{{ view_id|safe }}">
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="bulkUpdateModal{{view_id|safe}}"
|
||||
role="dialog"
|
||||
aria-labelledby="bulkUpdateModal{{view_id|safe}}"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="oh-modal__dialog" id="bulkUpdateModalBody{{view_id|safe}}"></div>
|
||||
</div>
|
||||
{% include "generic/export_fields_modal.html" %}
|
||||
<script>
|
||||
if (!$(".HTV").length) {
|
||||
$("#reloadMessagesButton").click()
|
||||
}
|
||||
</script>
|
||||
<button class="reload-record" id="{{view_id|safe}}Reload" hidden hx-get="{{request.path}}?{{saved_filters.urlencode}}" hx-target="#{{view_id|safe}}" hx-swap="outerHTML">
|
||||
</button>
|
||||
{% if show_filter_tags %} {% include "generic/filter_tags.html" %} {% endif %}
|
||||
{% if queryset|length %}
|
||||
{% if bulk_select_option %}
|
||||
{% include "generic/quick_actions.html" %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="oh-table_sticky--wrapper">
|
||||
{% if show_toggle_form %}
|
||||
<div class="oh-sticky-dropdown--header" style="z-index: 13;">
|
||||
<div class="oh-dropdown" x-data="{ open: false }">
|
||||
<button class="oh-sticky-dropdown_btn" @click="open = !open">
|
||||
<ion-icon
|
||||
name="ellipsis-vertical-sharp"
|
||||
role="img"
|
||||
class="md hydrated"
|
||||
aria-label="ellipsis vertical sharp"
|
||||
></ion-icon>
|
||||
</button>
|
||||
<div
|
||||
class="oh-dropdown__menu oh-sticky-table_dropdown"
|
||||
x-show="open"
|
||||
@click.outside="
|
||||
open = false
|
||||
$($el).closest('.oh-table_sticky--wrapper').parent().find('.reload-record').click();
|
||||
"
|
||||
>
|
||||
{{ toggle_form.as_list }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="fixed-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if bulk_select_option %}
|
||||
<th>
|
||||
<div class="centered-div" align="center">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="oh-input oh-input__checkbox bulk-list-table-row"
|
||||
onchange="
|
||||
$(this).closest('.fixed-table').find('.list-table-row').prop('checked',$(this).is(':checked')).change();
|
||||
$(document).ready(function () {
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
});
|
||||
"
|
||||
title="Select All"
|
||||
/>
|
||||
</div>
|
||||
</th>
|
||||
{% endif %}
|
||||
{% for cell in columns %}
|
||||
{% with cell_attr=header_attrs|get_item:cell.1 %}
|
||||
<th {% if cell.2 and not cell_attr %}style="width:220px!important;"{% endif %} {{cell_attr|safe}} id="{{view_id}}-{{ forloop.counter }}-{{cell.1}}-header">
|
||||
<div
|
||||
{% for sort_map in sortby_mapping %}
|
||||
{% if sort_map.0 == cell.0 %}
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&{{sortby_key}}={{sort_map.1}}&filter_applied=on"
|
||||
hx-target="#{{view_id}}"
|
||||
class="
|
||||
{% if request.sort_order == "asc" and request.sort_key == sort_map.1 %}
|
||||
arrow-up
|
||||
{% elif request.sort_order == "desc" and request.sort_key == sort_map.1 %}
|
||||
arrow-down
|
||||
{% else %}
|
||||
arrow-up-down
|
||||
{% endif %}
|
||||
"
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
>
|
||||
{{cell.0}}
|
||||
</div>
|
||||
</th>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% if options or option_method%}
|
||||
<th {{header_attrs.option|safe}}>
|
||||
{% trans "Options" %}
|
||||
</th>
|
||||
{% endif %}
|
||||
{% if actions or action_method %}
|
||||
<th class="lastTh" {{header_attrs.action|safe}}>
|
||||
{% trans "Actions" %}
|
||||
</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instance in queryset %}
|
||||
<tr
|
||||
data-instance-id="{{instance.id}}"
|
||||
{{row_attrs|format:instance|safe}}
|
||||
>
|
||||
{% if bulk_select_option %}
|
||||
<td class="p-0"onclick="event.stopPropagation()">
|
||||
<div class="{{row_status_class|format:instance|safe}} centered-div" align="center">
|
||||
<input
|
||||
type="checkbox"
|
||||
data-view-id="{{view_id|safe}}"
|
||||
class="oh-input oh-input__checkbox list-table-row"
|
||||
onchange="
|
||||
element = $(this)
|
||||
highlightRow(element);
|
||||
$(document).ready(function () {
|
||||
if (!element.is(':checked')) {
|
||||
removeId(element)
|
||||
}
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
});
|
||||
"
|
||||
title="{% trans "Select Row" %}"
|
||||
value = "{{instance.pk}}"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% for cell in columns %}
|
||||
{% with attribute=cell.1 index=forloop.counter %}
|
||||
<td>
|
||||
{% if not cell.2 %}
|
||||
{{instance|getattribute:attribute|selected_format:request.user.employee_get.employee_work_info.company_id|safe}}
|
||||
{% else %}
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{instance|getattribute:cell.2}}"
|
||||
class="oh-profile__image"
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">
|
||||
{{instance|getattribute:attribute}}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% if options or option_method %}
|
||||
<td onclick="event.stopPropagation()">
|
||||
{% if not option_method %}
|
||||
<div class="oh-btn-group">
|
||||
{% for option in options %}
|
||||
{% if option.accessibility|accessibility:instance %}
|
||||
<a
|
||||
href="#"
|
||||
title="{{option.option|safe}}"
|
||||
{{option.attrs|format:instance|safe}}
|
||||
>
|
||||
<ion-icon name="{{option.icon}}"></ion-icon>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %} {{instance|getattribute:option_method|safe}} {% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if actions or action_method %}
|
||||
<td class="lastTd" onclick="event.stopPropagation()">
|
||||
{% if not action_method %}
|
||||
<div class="oh-btn-group">
|
||||
{% for action in actions %}
|
||||
{% if action.accessibility|accessibility:instance %}
|
||||
<a
|
||||
title="{{action.action|safe}}"
|
||||
{{action.attrs|format:instance|safe}}
|
||||
>
|
||||
<ion-icon name="{{action.icon}}"></ion-icon>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %} {{instance|getattribute:action_method|safe}} {% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% if queryset.paginator.count %}
|
||||
<div class="oh-pagination">
|
||||
<span
|
||||
class="oh-pagination__page"
|
||||
data-toggle="modal"
|
||||
data-target="#addEmployeeModal"
|
||||
>{% trans "Page" %} {{queryset.number}} {% trans "of" %}
|
||||
{{queryset.paginator.num_pages}}</span
|
||||
>
|
||||
|
||||
<nav class="oh-pagination__nav">
|
||||
<div class="oh-pagination__input-container me-3">
|
||||
<span class="oh-pagination__label me-1">{% trans "Page" %}</span>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
class="oh-pagination__input"
|
||||
value="{{queryset.number}}"
|
||||
min="1"
|
||||
name="page"
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&filter_applied=on"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#{{view_id|safe}}"
|
||||
/>
|
||||
<span class="oh-pagination__label"
|
||||
>{% trans "of" %} {{queryset.paginator.num_pages}}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<ul class="oh-pagination__items" data-search-url="{{search_url}}">
|
||||
{% if queryset.has_previous %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&page=1&filter_applied=on"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#{{view_id|safe}}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "First" %}</a
|
||||
>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&page={{ queryset.previous_page_number }}&filter_applied=on"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#{{view_id|safe}}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Previous" %}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %} {% if queryset.has_next %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&page={{ queryset.next_page_number }}&filter_applied=on"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#{{view_id|safe}}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Next" %}</a
|
||||
>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-get="{{search_url}}?{{saved_filters.urlencode}}&page={{ queryset.paginator.num_pages }}&filter_applied=on"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#{{view_id|safe}}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Last" %}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<script>
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
var tabId = $("#{{view_id}}").closest(".oh-tabs__content").attr("id");
|
||||
var badge = $(`#badge-${tabId}`);
|
||||
var count = "{{queryset.paginator.count}}";
|
||||
var label = badge.attr("data-badge-label") || "";
|
||||
var title = count + " " + label;
|
||||
badge.html(count);
|
||||
badge.attr("title", title);
|
||||
</script>
|
||||
{% if bulk_select_option %}
|
||||
<script>
|
||||
selectSelected("#{{view_id|safe}}",'{{selected_instances_key_id}}')
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<script>
|
||||
$("ul[data-search-url] a").click(function (e) {
|
||||
e.preventDefault();
|
||||
const url = $(this).attr("hx-get")
|
||||
const $urlObj = $('<a>', { href: url });
|
||||
const searchParams = new URLSearchParams($urlObj[0].search);
|
||||
|
||||
let lastPageParam = null;
|
||||
let lastPageValue = 1;
|
||||
|
||||
searchParams.forEach((value, param) => {
|
||||
if (param === "page") {
|
||||
lastPageParam = param;
|
||||
lastPageValue = value.split(",").pop();
|
||||
}
|
||||
});
|
||||
|
||||
form = $(`form[hx-get="{{search_url}}"]`)
|
||||
pageInput = form.find("#pageInput")
|
||||
pageInput.attr("name",lastPageParam)
|
||||
pageInput.attr("value",lastPageValue)
|
||||
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
attrAction = `{{header_attrs.action|safe}}`
|
||||
if (!attrAction){
|
||||
const widths = [];
|
||||
let thWidth = 0;
|
||||
$('#{{view_id}} .lastTd').each(function () {
|
||||
widths.push(this.scrollWidth);
|
||||
$(this).css('overflow', 'hidden');
|
||||
});
|
||||
widths.sort().reverse();
|
||||
if (widths.length) {
|
||||
thWidth = widths[0];
|
||||
}
|
||||
$('#{{view_id}} .lastTh').css("width", `${thWidth}px`);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
{% if row_status_indications %}
|
||||
<div class="d-flex flex-row-reverse">
|
||||
{% for indication in row_status_indications %}
|
||||
<span class="m-1" style="cursor: pointer;margin-left: 7px;" {{indication.2|safe}}>
|
||||
<span class="oh-dot oh-dot--small me-1 {{indication.0}}"></span>
|
||||
{{indication.1}}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="oh-wrapper" align="center" style="margin-top: 7vh; margin-bottom:7vh;">
|
||||
<div align="center">
|
||||
<img src="{% static "images/ui/search.svg" %}" class="oh-404__image" alt="Page not found. 404.">
|
||||
<h1 class="oh-404__title">{% trans "No Records found" %}</h1>
|
||||
<p class="oh-404__subtitle">
|
||||
{% trans "No records found." %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -14,7 +14,7 @@
|
||||
addToSelectedId({{select_all_ids|safe}},'{{selected_instances_key_id}}');
|
||||
selectSelected('#{{view_id|safe}}','{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'));
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
"
|
||||
style="cursor: pointer;">
|
||||
<span class="label"
|
||||
@@ -33,7 +33,7 @@
|
||||
$('#{{selected_instances_key_id}}').attr('data-ids',JSON.stringify([]));
|
||||
selectSelected('#{{view_id|safe}}','{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'));
|
||||
reloadSelectedCount($('.count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
|
||||
$('#{{view_id}} .list-table-row').prop('checked',false);
|
||||
$('#{{view_id}} .highlight-selected').removeClass('highlight-selected');
|
||||
$('#{{view_id}} .bulk-list-table-row').prop('checked',false);
|
||||
|
||||
@@ -12,6 +12,7 @@ import types
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.context_processors import PermWrapper
|
||||
from django.db.models.utils import AltersData
|
||||
from django.template.defaultfilters import register
|
||||
|
||||
from horilla.config import import_method
|
||||
@@ -63,7 +64,15 @@ def getattribute(value, attr: str):
|
||||
result = ""
|
||||
attrs = attr.split("__")
|
||||
for attr in attrs:
|
||||
if hasattr(value, str(attr)):
|
||||
if isinstance(
|
||||
value,
|
||||
AltersData,
|
||||
) and hasattr(value, "through"):
|
||||
result = []
|
||||
queryset = value.all()
|
||||
for record in queryset:
|
||||
result.append(getattribute(record, attr))
|
||||
elif hasattr(value, str(attr)):
|
||||
result = getattr(value, attr)
|
||||
if isinstance(result, types.MethodType):
|
||||
result = result()
|
||||
@@ -127,4 +136,6 @@ def get_item(dictionary: dict, key: str):
|
||||
"""
|
||||
get_item method to access from dictionary
|
||||
"""
|
||||
return dictionary.get(key, "")
|
||||
if dictionary:
|
||||
return dictionary.get(key, "")
|
||||
return ""
|
||||
|
||||
Reference in New Issue
Block a user