[UPDT] HORILLA VIEWS: Bulk select widget design

This commit is contained in:
Horilla
2024-09-11 15:05:30 +05:30
parent 1694f85d8f
commit 6feacbb954
4 changed files with 92 additions and 261 deletions

View File

@@ -130,6 +130,16 @@ class DynamicBulkUpdateForm(forms.Form):
)
continue
elif not getattribute(val, "related_model"):
if isinstance(val, models.models.CharField) and val.choices:
self.fields[key] = forms.ChoiceField(
choices=val.choices,
widget=forms.Select(
attrs={"class": "oh-select oh-select-2 w-100"}
),
label=val.verbose_name.capitalize(),
required=False,
)
continue
self.fields[key] = field(
widget=widget,
label=val.verbose_name.capitalize(),

View File

@@ -827,11 +827,16 @@ class HorillaFormView(FormView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.form_class_path = (
self.get_form().__class__.__module__ + "." + self.form.__class__.__name__
)
context["dynamic_create_fields"] = self.dynamic_create_fields
context["form_class_path"] = self.form_class_path
context["view_id"] = self.view_id
pk = self.form.instance.pk
pk = None
if self.form.instance:
pk = self.form.instance.pk
# next/previous option in the forms
if pk and self.request.GET.get(self.ids_key):
instance_ids = eval(str(self.request.GET.get(self.ids_key)))
@@ -852,75 +857,75 @@ class HorillaFormView(FormView):
return context
def get_form(self, form_class=None):
pk = self.kwargs.get("pk")
instance = self.model.objects.filter(pk=pk).first()
data = None
files = None
if self.request.method == "POST":
data = self.request.POST
files = self.request.FILES
form = self.form_class(data, files, instance=instance)
if not hasattr(self, "form"):
pk = self.kwargs.get("pk")
instance = self.model.objects.filter(pk=pk).first()
data = None
files = None
if self.request.method == "POST":
data = self.request.POST
files = self.request.FILES
form = self.form_class(data, files, instance=instance)
if self.is_dynamic_create_view:
setattr(type(form), "save", save)
if self.is_dynamic_create_view:
setattr(type(form), "save", save)
self.form_class_path = form.__class__.__module__ + "." + form.__class__.__name__
if self.request.method == "GET":
[
(
"employee_id",
FormView,
)
]
for dynamic_tuple in self.dynamic_create_fields:
view = dynamic_tuple[1]
view.display_title = "Dynamic create"
field = dynamic_tuple[0]
key = self.request.session.session_key + "cbv" + field
CACHE.set(
key,
{
"dynamic_field": field,
"value": getattribute(form.instance, field),
"model": form._meta.model,
},
)
from django.urls import path
from horilla.urls import urlpatterns
urlpatterns.append(
path(
f"dynamic-path-{field}-{self.request.session.session_key}",
view.as_view(),
name=f"dynamic-path-{field}-{self.request.session.session_key}",
if self.request.method == "GET":
[
(
"employee_id",
FormView,
)
)
queryset = form.fields[field].queryset
choices = [(instance.id, instance) for instance in queryset]
choices.insert(0, ("", "Select option"))
choices.append(("dynamic_create", "Dynamic create"))
form.fields[field] = forms.ChoiceField(
choices=choices,
label=form.fields[field].label,
required=form.fields[field].required,
widget=forms.Select(attrs=form.fields[field].widget.attrs),
)
if pk:
form.instance = instance
title = str(instance)
if self.form_disaply_attr:
title = getattribute(instance, self.form_disaply_attr)
if instance:
self.form_class.verbose_name = title
else:
self.form_class.verbose_name = self.new_display_title
form.close_button_attrs = self.close_button_attrs
form.submit_button_attrs = self.submit_button_attrs
CACHE.get(self.request.session.session_key + "cbv")[HorillaFormView] = form
self.form = form
return form
]
for dynamic_tuple in self.dynamic_create_fields:
view = dynamic_tuple[1]
view.display_title = "Dynamic create"
field = dynamic_tuple[0]
key = self.request.session.session_key + "cbv" + field
CACHE.set(
key,
{
"dynamic_field": field,
"value": getattribute(form.instance, field),
"model": form._meta.model,
},
)
from django.urls import path
from horilla.urls import urlpatterns
urlpatterns.append(
path(
f"dynamic-path-{field}-{self.request.session.session_key}",
view.as_view(),
name=f"dynamic-path-{field}-{self.request.session.session_key}",
)
)
queryset = form.fields[field].queryset
choices = [(instance.id, instance) for instance in queryset]
choices.insert(0, ("", "Select option"))
choices.append(("dynamic_create", "Dynamic create"))
form.fields[field] = forms.ChoiceField(
choices=choices,
label=form.fields[field].label,
required=form.fields[field].required,
widget=forms.Select(attrs=form.fields[field].widget.attrs),
)
if pk:
form.instance = instance
title = str(instance)
if self.form_disaply_attr:
title = getattribute(instance, self.form_disaply_attr)
if instance:
self.form_class.verbose_name = title
else:
self.form_class.verbose_name = self.new_display_title
form.close_button_attrs = self.close_button_attrs
form.submit_button_attrs = self.submit_button_attrs
CACHE.get(self.request.session.session_key + "cbv")[HorillaFormView] = form
self.form = form
return self.form
@method_decorator(hx_request_required, name="dispatch")

View File

@@ -16,102 +16,7 @@
}
</script>
{% if bulk_select_option %}
<div class="d-flex justify-content-between">
<div>
<div class="oh-checkpoint-badge text-success"
onclick="
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}}');
"
style="cursor: pointer;">
{% trans "Select All" %} ({{queryset.paginator.count}})
</div>
<div
id="unselect_{{view_id}}"
class="oh-checkpoint-badge text-secondary d-none"
style="cursor: pointer;"
onclick="
$('#{{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}}');
$('#{{view_id}} .list-table-row').prop('checked',false);
$('#{{view_id}} .highlight-selected').removeClass('highlight-selected');
$('#{{view_id}} .bulk-list-table-row').prop('checked',false);
"
>
{% trans "Unselect All" %}
</div>
<div class="oh-checkpoint-badge text-danger d-none"
style="cursor: pointer;"
>
<span id="count_{{view_id}}">
0
</span> {% trans "Selected" %}
</div>
<div
id="export_{{view_id}}"
class="oh-checkpoint-badge text-info d-none"
style="cursor: pointer;"
data-toggle="oh-modal-toggle"
data-target="#exportFields{{view_id|safe}}"
>
{% trans "Export" %}
</div>
{% if bulk_path %}
<div
id="bulk_udate_{{view_id}}"
class="oh-checkpoint-badge text-warning d-none"
style="cursor: pointer;"
data-toggle="oh-modal-toggle"
data-target="#bulkUpdateModal{{view_id|safe}}"
onclick="
ids = $('#{{selected_instances_key_id}}').attr('data-ids')
$('#bulk_update_get_form{{view_id}}').closest('form').find('[name=instance_ids]').val(ids);
$('#bulk_update_get_form{{view_id}}').click()
"
>
{% trans "Update" %}
</div>
<form
hx-get="/{{bulk_path}}"
hx-target="#bulkUpdateModalBody{{view_id|safe}}">
<input type="hidden" name="instance_ids">
<button type="submit" id="bulk_update_get_form{{view_id}}" hidden>
</button>
</form>
{% endif %}
{% for filter in stored_filters %}
<div class="oh-hover-btn-container"
hx-get="{{request.path}}?{{filter.urlencode}}"
hx-target="#{{view_id|safe}}" hx-swap="outerHTML"
>
<button class="oh-hover-btn" style="
cursor: pointer;
border: solid 2px {{filter.color}};
color: {{filter.color}} !important;
">
{{filter.title}}
</button>
<div class="oh-hover-btn-drawer" onclick="event.stopPropagation()">
<button class="oh-hover-btn__small" onclick="$('#savedFilterModal').addClass('oh-modal--show')" hx-get="{% url "saved-filter-update" filter.id %}" hx-target="#SavedFilterFormTarget" hx-swap="innerHTML"><ion-icon name="create-outline"></ion-icon></button>
<button class="oh-hover-btn__small" onclick="$(this).parent().find('button:hidden').click();$(this).closest('.oh-hover-btn-container').remove()" ><ion-icon name="trash-outline"></ion-icon></button>
<button hidden hx-get="{% url "delete-saved-filter" filter.id %}" hx-swap="none"></button>
</div>
</div>
{% endfor %}
</div>
{% 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>
{% include "generic/quick_actions.html" %}
{% endif %}
<button class="reload-record" hidden hx-get="{{request.path}}?{{request.GET.urlencode}}" hx-target="#{{view_id|safe}}" hx-swap="outerHTML">
</button>
@@ -146,7 +51,7 @@
<div class="oh-tabs__input-badge-container">
<span
class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round mr-1"
title="5 Candidates"
title="{{group.list.paginator.count}} {% trans "Records" %}"
>
{{group.list.paginator.count}}
</span>
@@ -178,6 +83,7 @@
$(this).closest('.oh-sticky-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}}'));
});
"
title="Select All"
@@ -229,6 +135,7 @@
removeId(element)
}
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
reloadSelectedCount($('.count_{{view_id|safe}}'));
});
"
value = "{{instance.pk}}"
@@ -416,6 +323,8 @@
</nav>
</div>
<script>
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
reloadSelectedCount($('.count_{{view_id|safe}}'));
var tabId = $("#{{view_id}}").closest(".oh-tabs__content").attr("id")
let badge = $(`#badge-${tabId}`)
let count = "{{queryset.paginator.count}}"

View File

@@ -21,103 +21,7 @@
{% if show_filter_tags %} {% include "generic/filter_tags.html" %} {% endif %}
{% if queryset|length %}
{% if bulk_select_option %}
<div class="d-flex justify-content-between mb-2">
<div>
<div class="oh-checkpoint-badge text-success"
onclick="
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}}');
"
style="cursor: pointer;">
{% trans "Select All" %} ({{queryset.paginator.count}})
</div>
<div
id="unselect_{{view_id}}"
class="oh-checkpoint-badge text-secondary d-none"
style="cursor: pointer;"
onclick="
$('#{{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}}');
$('#{{view_id}} .list-table-row').prop('checked',false);
$('#{{view_id}} .highlight-selected').removeClass('highlight-selected');
$('#{{view_id}} .bulk-list-table-row').prop('checked',false);
"
>
{% trans "Unselect All" %}
</div>
<div class="oh-checkpoint-badge text-danger d-none"
style="cursor: pointer;"
>
<span id="count_{{view_id}}">
0
</span> {% trans "Selected" %}
</div>
<div
id="export_{{view_id}}"
class="oh-checkpoint-badge text-info d-none"
style="cursor: pointer;"
data-toggle="oh-modal-toggle"
data-target="#exportFields{{view_id|safe}}"
>
{% trans "Export" %}
</div>
{% if bulk_path %}
<div
id="bulk_udate_{{view_id}}"
class="oh-checkpoint-badge text-warning d-none"
style="cursor: pointer;"
data-toggle="oh-modal-toggle"
data-target="#bulkUpdateModal{{view_id|safe}}"
onclick="
ids = $('#{{selected_instances_key_id}}').attr('data-ids')
$('#bulk_update_get_form{{view_id}}').closest('form').find('[name=instance_ids]').val(ids);
$('#bulk_update_get_form{{view_id}}').click()
"
>
{% trans "Update" %}
</div>
<form
hx-get="/{{bulk_path}}"
hx-target="#bulkUpdateModalBody{{view_id|safe}}">
<input type="hidden" name="instance_ids">
<button type="submit" id="bulk_update_get_form{{view_id}}" hidden>
</button>
</form>
{% endif %}
{% for filter in stored_filters %}
<div class="oh-hover-btn-container"
hx-get="{{request.path}}?{{filter.urlencode}}"
hx-target="#{{view_id|safe}}" hx-swap="outerHTML"
>
<button class="oh-hover-btn" style="
cursor: pointer;
border: solid 2px {{filter.color}};
color: {{filter.color}} !important;
">
{{filter.title}}
</button>
<div class="oh-hover-btn-drawer" onclick="event.stopPropagation()">
<button class="oh-hover-btn__small" onclick="$('#savedFilterModal').addClass('oh-modal--show')" hx-get="{% url "saved-filter-update" filter.id %}" hx-target="#SavedFilterFormTarget" hx-swap="innerHTML"><ion-icon name="create-outline"></ion-icon></button>
<button class="oh-hover-btn__small" onclick="$(this).parent().find('button:hidden').click();$(this).closest('.oh-hover-btn-container').remove()" ><ion-icon name="trash-outline"></ion-icon></button>
<button hidden hx-get="{% url "delete-saved-filter" filter.id %}" hx-swap="none"></button>
</div>
</div>
{% endfor %}
</div>
{% 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>
{% include "generic/quick_actions.html" %}
{% endif %}
@@ -166,6 +70,7 @@
$(this).closest('.oh-sticky-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}}'));
});
"
title="Select All"
@@ -241,6 +146,7 @@
removeId(element)
}
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
reloadSelectedCount($('.count_{{view_id|safe}}'));
});
"
value = "{{instance.pk}}"
@@ -387,6 +293,7 @@
</div>
<script>
reloadSelectedCount($('#count_{{view_id|safe}}'),'{{selected_instances_key_id}}');
reloadSelectedCount($('.count_{{view_id|safe}}'));
var tabId = $("#{{view_id}}").closest(".oh-tabs__content").attr("id");
let badge = $(`#badge-${tabId}`);
let count = "{{queryset.paginator.count}}";