Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions is_core/generic_views/inlines/inline_table_views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
from typing import Dict, Any, List

from django.forms.models import _get_foreign_key
from django.urls import reverse

from is_core.generic_views.table_views import DjangoTableViewMixin, BaseModelTableViewMixin
from is_core.generic_views.inlines.base import RelatedInlineView
from is_core.utils import get_export_types_with_content_type
from is_core.rest.datastructures import ModelFlatRestFields


class BaseModelInlineTableViewMixin:

template_name = 'is_core/forms/inline_table.html'
inline_bulk_change = False
inline_export = False

def _get_field_labels(self):
return (
Expand All @@ -26,6 +33,13 @@ def _get_export_fields(self):
else self.export_fields
)

def _get_export_types(self) -> List | None:
return (
self.related_core.get_export_types(self.request) if self.related_core and
getattr(self, 'export_types', None) is None
else getattr(self, 'export_types', None)
)

def _get_list_per_page(self):
list_per_page = self.related_core.get_list_per_page(self.request) if self.related_core else None
return list_per_page if list_per_page is not None else super()._get_list_per_page()
Expand All @@ -42,6 +56,57 @@ def get_title(self):
'verbose_name_plural': self.get_verbose_name_plural()
} if self.title is None else self.title

def is_bulk_change_enabled(self) -> bool:
return (
self.inline_bulk_change and
hasattr(self.related_core, 'is_bulk_change_enabled') and
self.related_core.is_bulk_change_enabled() and
self.related_core.ui_patterns.get(self.related_core.get_bulk_change_url_name()).has_permission(
'get', self.request
)
)

def get_bulk_change_snippet_name(self) -> str:
return '-'.join(('default', self.related_core.menu_group, 'form'))

def get_bulk_change_form_url(self) -> str | None:
if not self.is_bulk_change_enabled():
return None
return reverse(
''.join(('IS:', self.related_core.get_bulk_change_url_name(), '-', self.related_core.menu_group))
)

def _generate_rest_export_fieldset(self) -> ModelFlatRestFields:
return ModelFlatRestFields.create_from_flat_list(
list(self._get_allowed_export_fields()), self.model
)

def is_export_enabled(self) -> bool:
"""
Returns whether export is enabled for this inline table.
Checks both the inline_export flag and if export types/fields are available.
"""
return (
self.inline_export and
self._get_export_types() and
self._get_allowed_export_fields()
)

def get_context_data(self, **kwargs) -> Dict[str, Any]:
context_data = super().get_context_data(**kwargs)
context_data.update({
'inline_bulk_change': self.is_bulk_change_enabled(),
'bulk_change_snippet_name': self.get_bulk_change_snippet_name(),
'bulk_change_form_url': self.get_bulk_change_form_url(),
'inline_export_enabled': self.is_export_enabled(),
})
if self.is_export_enabled():
context_data.update({
'rest_export_fieldset': self._generate_rest_export_fieldset(),
'export_types': get_export_types_with_content_type(self._get_export_types()),
})
return context_data


class BaseModelInlineTableView(BaseModelInlineTableViewMixin, BaseModelTableViewMixin, RelatedInlineView):
pass
Expand Down
52 changes: 51 additions & 1 deletion is_core/templates/is_core/forms/inline_table.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
{% load i18n utils permissions %}

{% block inline-table %}
<style>
.table th.select-all {
width: 30px;
text-align: center;
padding: 8px 4px;
}
.table th.select-all input[type="checkbox"],
.table td.select input[type="checkbox"] {
margin: 0;
width: 16px;
height: 16px;
}
</style>
<div class="table-inline-responsive">
{% block tabs-menu-wrapper %}{% endblock %}
{% block table-paginator %}
Expand Down Expand Up @@ -59,6 +72,25 @@

{% block inline-table-buttons %}
<ul class="inline-list">
{% block export-menu %}
{% if inline_export_enabled and export_types %}
<li>
<div class="dropdown columns-dropdown">
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" title="{% trans 'Export files in selected format' %}">
<i class="fa fa-file-export"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
{% for title, type, serialization_format, content_type in export_types %}
<li>
<a href="{{ api_url }}?_accept={{ content_type }}&amp;_serialization_format={{ serialization_format }}&amp;_fields={{ rest_export_fieldset }}{% if query_string_filter %}&amp;{{ query_string_filter }}{% endif %}&amp;_background_serialization=1" target="_blank" class="export" data-type="{{ type }}">{{ title }}</a>
</li>
{% endfor %}
</ul>
</div>
</li>
{% endif %}
{% endblock %}

{% block column-manager %}
{% if enable_column_manager %}
<li>
Expand All @@ -70,6 +102,21 @@
{% endif %}
{% endblock %}

{% block bulk-change %}
{% if inline_bulk_change %}
<li>
<span class="btn btn-primary"
id="bulk-change-{{ table_slug }}"
data-form-snippet="{{ bulk_change_snippet_name }}"
data-form-url="{{ bulk_change_form_url }}"
data-api-url="{{ api_url }}"
data-bulk-error-message="{% trans 'Please fix errors for following objects: %s' %}"
title="{% trans 'Update selected rows' %}"
><i class="fa fa-stream"></i> {% trans 'Bulk change' %}</span>
</li>
{% endif %}
{% endblock %}

{% block inline-table-rest-buttons %}{% endblock %}
</ul>
<ul class="inline-list inline-list-right table-buttons">
Expand All @@ -86,10 +133,13 @@
{% endblock %}

{% block table %}
<table class="{% block table-classes %}grid js-grid table table-striped{% endblock %}" data-resource="{{ api_url }}{% if query_string_filter %}?{{ query_string_filter }}{% endif %}" data-model="{{ module_name|capfirst }}" data-cols="{{ fields|join:',' }}" data-rest-fields="{{ rest_fieldset }}" data-confirm="{% trans 'Do you really want to delete &#37;s?' %}" data-btn-yes="{% trans 'Yes' %}" data-btn-no="{% trans 'No' %}" data-context="{{ menu_group_pattern_name }}" data-confirm-title="{% trans 'Are you sure?' %}"{% if enable_column_manager %} data-columns-manager="columns-manager-{{ table_slug }}"{% endif %} id="table-{{ table_slug }}" {% block table-attributes %}{% endblock %}>
<table class="{% block table-classes %}grid js-grid table table-striped{% endblock %}" data-resource="{{ api_url }}{% if query_string_filter %}?{{ query_string_filter }}{% endif %}" data-model="{{ module_name|capfirst }}" data-cols="{{ fields|join:',' }}" data-rest-fields="{{ rest_fieldset }}" data-confirm="{% trans 'Do you really want to delete &#37;s?' %}" data-btn-yes="{% trans 'Yes' %}" data-btn-no="{% trans 'No' %}" data-context="{{ menu_group_pattern_name }}" data-confirm-title="{% trans 'Are you sure?' %}"{% if enable_column_manager %} data-columns-manager="columns-manager-{{ table_slug }}"{% endif %}{% if inline_bulk_change %} data-bulk-change="bulk-change-{{ table_slug }}" data-row-selectable="true"{% endif %} id="table-{{ table_slug }}" {% block table-attributes %}{% endblock %}>
<thead>
{% block table-header %}
<tr>
{% if inline_bulk_change %}
<th class="select-all"><input id="select-all-{{ table_slug }}" class="select-all" type="checkbox"></th>
{% endif %}
{% for header in headers %}
<th class="{{ header.field_name }}">
<span{% if header.order_by %} class="sortable" data-col="{{ header.order_by }}"{% endif %}>{{ header.text|capfirst }}</span>
Expand Down