Skip to content

Commit ac63970

Browse files
committed
inline_table_expansion, added support for export and inlines
1 parent c74e05c commit ac63970

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

is_core/generic_views/inlines/inline_table_views.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
from typing import Dict, Any, List
2+
13
from django.forms.models import _get_foreign_key
4+
from django.urls import reverse
25

36
from is_core.generic_views.table_views import DjangoTableViewMixin, BaseModelTableViewMixin
47
from is_core.generic_views.inlines.base import RelatedInlineView
8+
from is_core.utils import get_export_types_with_content_type
9+
from is_core.rest.datastructures import ModelFlatRestFields
510

611

712
class BaseModelInlineTableViewMixin:
813

914
template_name = 'is_core/forms/inline_table.html'
15+
inline_bulk_change = False
16+
inline_export = False
1017

1118
def _get_field_labels(self):
1219
return (
@@ -26,6 +33,20 @@ def _get_export_fields(self):
2633
else self.export_fields
2734
)
2835

36+
def _get_export_types(self) -> List | None:
37+
return (
38+
self.related_core.get_export_types(self.request) if self.related_core and
39+
getattr(self, 'export_types', None) is None
40+
else getattr(self, 'export_types', None)
41+
)
42+
43+
def _get_export_types(self) -> List | None:
44+
return (
45+
self.related_core.get_export_types(self.request) if self.related_core and
46+
getattr(self, 'export_types', None) is None
47+
else getattr(self, 'export_types', None)
48+
)
49+
2950
def _get_list_per_page(self):
3051
list_per_page = self.related_core.get_list_per_page(self.request) if self.related_core else None
3152
return list_per_page if list_per_page is not None else super()._get_list_per_page()
@@ -42,6 +63,57 @@ def get_title(self):
4263
'verbose_name_plural': self.get_verbose_name_plural()
4364
} if self.title is None else self.title
4465

66+
def is_bulk_change_enabled(self) -> bool:
67+
return (
68+
self.inline_bulk_change and
69+
hasattr(self.related_core, 'is_bulk_change_enabled') and
70+
self.related_core.is_bulk_change_enabled() and
71+
self.related_core.ui_patterns.get(self.related_core.get_bulk_change_url_name()).has_permission(
72+
'get', self.request
73+
)
74+
)
75+
76+
def get_bulk_change_snippet_name(self) -> str:
77+
return '-'.join(('default', self.related_core.menu_group, 'form'))
78+
79+
def get_bulk_change_form_url(self) -> str | None:
80+
if not self.is_bulk_change_enabled():
81+
return None
82+
return reverse(
83+
''.join(('IS:', self.related_core.get_bulk_change_url_name(), '-', self.related_core.menu_group))
84+
)
85+
86+
def _generate_rest_export_fieldset(self) -> ModelFlatRestFields:
87+
return ModelFlatRestFields.create_from_flat_list(
88+
list(self._get_allowed_export_fields()), self.model
89+
)
90+
91+
def is_export_enabled(self) -> bool:
92+
"""
93+
Returns whether export is enabled for this inline table.
94+
Checks both the inline_export flag and if export types/fields are available.
95+
"""
96+
return (
97+
self.inline_export and
98+
self._get_export_types() and
99+
self._get_allowed_export_fields()
100+
)
101+
102+
def get_context_data(self, **kwargs) -> Dict[str, Any]:
103+
context_data = super().get_context_data(**kwargs)
104+
context_data.update({
105+
'inline_bulk_change': self.is_bulk_change_enabled(),
106+
'bulk_change_snippet_name': self.get_bulk_change_snippet_name(),
107+
'bulk_change_form_url': self.get_bulk_change_form_url(),
108+
'inline_export_enabled': self.is_export_enabled(),
109+
})
110+
if self.is_export_enabled():
111+
context_data.update({
112+
'rest_export_fieldset': self._generate_rest_export_fieldset(),
113+
'export_types': get_export_types_with_content_type(self._get_export_types()),
114+
})
115+
return context_data
116+
45117

46118
class BaseModelInlineTableView(BaseModelInlineTableViewMixin, BaseModelTableViewMixin, RelatedInlineView):
47119
pass

is_core/templates/is_core/forms/inline_table.html

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
{% load i18n utils permissions %}
22

33
{% block inline-table %}
4+
<style>
5+
.table th.select-all {
6+
width: 30px;
7+
text-align: center;
8+
padding: 8px 4px;
9+
}
10+
.table th.select-all input[type="checkbox"],
11+
.table td.select input[type="checkbox"] {
12+
margin: 0;
13+
width: 16px;
14+
height: 16px;
15+
}
16+
</style>
417
<div class="table-inline-responsive">
518
{% block tabs-menu-wrapper %}{% endblock %}
619
{% block table-paginator %}
@@ -59,6 +72,25 @@
5972

6073
{% block inline-table-buttons %}
6174
<ul class="inline-list">
75+
{% block export-menu %}
76+
{% if inline_export_enabled and export_types %}
77+
<li>
78+
<div class="dropdown columns-dropdown">
79+
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" title="{% trans 'Export files in selected format' %}">
80+
<i class="fa fa-file-export"></i> <span class="caret"></span>
81+
</button>
82+
<ul class="dropdown-menu" role="menu">
83+
{% for title, type, serialization_format, content_type in export_types %}
84+
<li>
85+
<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>
86+
</li>
87+
{% endfor %}
88+
</ul>
89+
</div>
90+
</li>
91+
{% endif %}
92+
{% endblock %}
93+
6294
{% block column-manager %}
6395
{% if enable_column_manager %}
6496
<li>
@@ -70,6 +102,21 @@
70102
{% endif %}
71103
{% endblock %}
72104

105+
{% block bulk-change %}
106+
{% if inline_bulk_change %}
107+
<li>
108+
<span class="btn btn-primary"
109+
id="bulk-change-{{ table_slug }}"
110+
data-form-snippet="{{ bulk_change_snippet_name }}"
111+
data-form-url="{{ bulk_change_form_url }}"
112+
data-api-url="{{ api_url }}"
113+
data-bulk-error-message="{% trans 'Please fix errors for following objects: %s' %}"
114+
title="{% trans 'Update selected rows' %}"
115+
><i class="fa fa-stream"></i> {% trans 'Bulk change' %}</span>
116+
</li>
117+
{% endif %}
118+
{% endblock %}
119+
73120
{% block inline-table-rest-buttons %}{% endblock %}
74121
</ul>
75122
<ul class="inline-list inline-list-right table-buttons">
@@ -86,10 +133,13 @@
86133
{% endblock %}
87134

88135
{% block table %}
89-
<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 %}>
136+
<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 %}>
90137
<thead>
91138
{% block table-header %}
92139
<tr>
140+
{% if inline_bulk_change %}
141+
<th class="select-all"><input id="select-all-{{ table_slug }}" class="select-all" type="checkbox"></th>
142+
{% endif %}
93143
{% for header in headers %}
94144
<th class="{{ header.field_name }}">
95145
<span{% if header.order_by %} class="sortable" data-col="{{ header.order_by }}"{% endif %}>{{ header.text|capfirst }}</span>

0 commit comments

Comments
 (0)