Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve html templates for admin pages #71

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 12 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
=======
History
=======
UNRELEASED
------------------
* Fix progress bar on changeview for ImportJob and ExportJob
* Improve celery-import-result page

* Add displaying resources for import form
* Fix autofill `Format` by file extension
* Add `Totals` section
* Remove extra loop if errors in input file (https://github.com/saritasa-nest/django-import-export-extensions/issues/74)

* Fixed display of progress bar when task is waiting to run (https://github.com/saritasa-nest/django-import-export-extensions/issues/68)
* Improve progress bar style (https://github.com/saritasa-nest/django-import-export-extensions/issues/72)

1.0.1 (2024-11-08)
------------------
Expand Down
47 changes: 34 additions & 13 deletions import_export_extensions/admin/mixins/import_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from import_export import admin as import_export_admin
from import_export import mixins as import_export_mixins
from import_export import resources as import_export_resources

from ... import models
from ..forms import ForceImportForm
Expand Down Expand Up @@ -170,24 +171,16 @@ def celery_import_action(
)

# GET: display Import Form
resources = [
resource_class(**resource_kwargs)
for resource_class in resource_classes
]

context.update(self.admin_site.each_context(request))

context["title"] = _("Import")
context["form"] = form
context["opts"] = self.model_info.meta
context["media"] = self.media + form.media
context["fields_list"] = [
(
resource.get_display_name(),
[f.column_name for f in resource.get_user_visible_fields()],
)
for resource in resources
]
context["fields_list"] = self._get_fields_list_for_resources(
resource_classes=resource_classes,
resource_kwargs=resource_kwargs,
)

request.current_app = self.admin_site.name
return TemplateResponse(
Expand Down Expand Up @@ -282,9 +275,16 @@ def celery_import_job_results_view(
context["confirm_form"] = Form()
else:
# display import form
resource_classes = self.get_import_resource_classes(request)
resource_kwargs = self.get_import_resource_kwargs(request)

context["import_form"] = ForceImportForm(
formats=self.get_import_formats(),
resources=self.get_import_resource_classes(request),
resources=resource_classes,
)
context["fields_list"] = self._get_fields_list_for_resources(
resource_classes=resource_classes,
resource_kwargs=resource_kwargs,
)

context.update(self.admin_site.each_context(request))
Expand Down Expand Up @@ -376,6 +376,27 @@ def _redirect_to_results_page(

return HttpResponseRedirect(redirect_to=url)

def _get_fields_list_for_resources(
self,
resource_classes: list[type[import_export_resources.ModelResource]],
resource_kwargs,
) -> list[tuple[str, list[str]]]:
"""Get fields list for resource classes."""
resources = [
resource_class(**resource_kwargs)
for resource_class in resource_classes
]
return [
(
resource.get_display_name(),
[
field.column_name
for field in resource.get_user_visible_fields()
],
)
for resource in resources
]

def changelist_view(
self,
request: WSGIRequest,
Expand Down
14 changes: 4 additions & 10 deletions import_export_extensions/admin/widgets.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

from django import forms
from django.template.loader import render_to_string


class ProgressBarWidget(forms.Widget):
Expand All @@ -9,6 +10,8 @@ class ProgressBarWidget(forms.Widget):

"""

template_name = "admin/import_export_extensions/progress_bar.html"

def __init__(self, *args, **kwargs):
"""Get ``ImportJob`` or ``ExportJob`` instance from kwargs.

Expand All @@ -28,16 +31,7 @@ def render(self, *args, **kwargs) -> str:
to send GET requests.

"""
progress_bar = f"""
<progress
value="0"
max="100"
id="progress-bar"
data-url="{self.url}">
</progress>
"""

return progress_bar
return render_to_string(self.template_name, {"job_url": self.url})

class Media:
"""Class with custom assets for widget."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ progress {
width: 100%;
-webkit-appearance: none;
border: none;
position:relative;
position: relative;
}
progress:before {
content: attr(data-label);
Expand All @@ -24,8 +24,13 @@ progress::-webkit-progress-bar {
background-color: var(--breadcrumbs-fg);
}
progress::-webkit-progress-value {
background-color: var(--breadcrumbs-bg);
background-color: var(--primary);
}
progress::-moz-progress-bar {
background-color: var(--breadcrumbs-bg);
}

html[data-theme="dark"]
progress::-webkit-progress-bar {
background-color: var(--darkened-bg);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
{% endblock %}

{% block breadcrumbs_last %}
<a href="{% url opts|admin_urlname:'export' %}?{{request.GET.urlencode}}">
<a href="{% url opts|admin_urlname:'export' %}?{{ request.GET.urlencode }}">
{% trans "Export" %}
</a>
&rsaquo; {% trans "Export results" %}
Expand All @@ -40,7 +40,7 @@ <h2>
<h2>
{% trans "You can download exported data with following link" %}
</h2>
<a href="{{ export_job.data_file.url }}" id="data_file">Download export data</a>
<a href="{{ export_job.data_file.url }}" id="data_file">{% trans "Download export data" %}</a>
{% endif %}
{% endblock %}
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

{% comment %}
Template to show status of export job.
Similar to job's admin page.

{% endcomment %}

{% block extrastyle %}
Expand All @@ -24,7 +22,7 @@


{% block breadcrumbs_last %}
<a href="{% url opts|admin_urlname:'export' %}?{{request.GET.urlencode}}">
<a href="{% url opts|admin_urlname:'export' %}?{{ request.GET.urlencode }}">
{% trans "Export" %}
</a>
&rsaquo;
Expand All @@ -35,37 +33,14 @@
<div>
<fieldset class="module aligned collapse">
<div class="form-row">
<label>Status</label><p id="current-job-status">{{ export_job.export_status|title }}</p>
<label>{% trans "Status" %}</label>
<p id="current-job-status">{{ export_job.export_status|title }}</p>
</div>

{% if export_job.export_status not in export_job.export_finished_statuses %}
<div class="form-row">
<label>Progress</label>
<p id="progress_bar_html">
<progress max="100" id="progress-bar" data-url="{{ export_job_url }}"></progress>
</p>
</div>
{% endif %}

{% if export_job.export_status == export_job.ExportStatus.EXPORTED %}
<div class="form-row">
<label>Totals</label>
<p>
{% for total, stat in export_job.result.totals.items %}
{{ total.title }}:&nbsp; <b>{{ stat }}</b><br>
{% endfor %}
</p>
</div>
{% endif %}

{% if export_job.export_status == export_job.ExportStatus.EXPORT_ERROR %}
<div class="form-row">
<label>Error</label>
<p><b>{{ export_job.error_message }}</b></p>
</div>
<div class="form-row">
<label>Traceback</label>
{{ export_job.traceback | linebreaks }}
<label>{% trans "Progress" %}</label>
{% include "admin/import_export_extensions/progress_bar.html" with job_url=export_job_url %}
</div>
{% endif %}
</fieldset>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'import_export_extensions/js/admin/admin.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static "import_export_extensions/css/admin/import_result_diff.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "import_export/import.css"" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "import_export/import.css" %}"/>
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{% if confirm_form %}
{{ confirm_form.media }}
{% else %}
{{ import_form.media }}
{% endif %}
{% endblock %}


{% block breadcrumbs_last %}
<a href="{% url opts|admin_urlname:'import' %}?{{request.GET.urlencode}}">
<a href="{% url opts|admin_urlname:'import' %}?{{ request.GET.urlencode }}">
{% trans "Import" %}
</a>
&rsaquo; {% trans "Import results" %}
Expand Down Expand Up @@ -50,6 +56,8 @@
<form action="{% url opts|admin_urlname:"import" %}?{{ request.GET.urlencode }}" method="post" enctype="multipart/form-data">
{% csrf_token %}

{% include "admin/import_export/resource_fields_list.html" with import_or_export="import" %}

<fieldset class="module aligned">
{% for field in import_form %}
<div class="form-row">
Expand Down Expand Up @@ -99,62 +107,66 @@ <h2>{% trans "Errors" %}</h2>
</li>
{% endfor %}
{% endfor %}
{% for invalid_row in result.invalid_rows %}
<h2>{% trans "Some rows failed to validate" %}</h2>
<h2>{% trans "Some rows failed to validate" %}</h2>

<p>{% trans "Please correct these errors in your data where possible, then reupload it using the form above." %}</p>
<table class="import-preview">
<thead>
<p>{% trans "Please correct these errors in your data where possible, then reupload it using the form above." %}</p>
<table class="import-preview">
<thead>
<tr>
<th>{% trans "Row" %}</th>
<th>{% trans "Errors" %}</th>
{% for field in result.diff_headers %}
<th>{{ field }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in result.invalid_rows %}
<tr>
<th>{% trans "Row" %}</th>
<th>{% trans "Errors" %}</th>
{% for field in result.diff_headers %}
<th>{{ field }}</th>
<td>{{ row.number }} </td>
<td class="errors">
<span class="validation-error-count">{{ row.error_count }}</span>
<div class="validation-error-container">
<ul class="validation-error-list">
{% for field_name, error_list in row.field_specific_errors.items %}
<li>
<span class="validation-error-field-label">{{ field_name }}</span>
<ul>
{% for error in error_list %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
{% if row.non_field_specific_errors %}
<li>
<span class="validation-error-field-label">{% trans "Non field specific" %}</span>
<ul>
{% for error in row.non_field_specific_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
</ul>
</div>
</td>
{% for field in row.values %}
<td>{{ field }}</td>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in result.invalid_rows %}
<tr>
<td>{{ row.number }} </td>
<td class="errors">
<span class="validation-error-count">{{ row.error_count }}</span>
<div class="validation-error-container">
<ul class="validation-error-list">
{% for field_name, error_list in row.field_specific_errors.items %}
<li>
<span class="validation-error-field-label">{{ field_name }}</span>
<ul>
{% for error in error_list %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
{% if row.non_field_specific_errors %}
<li>
<span class="validation-error-field-label">{% trans "Non field specific" %}</span>
<ul>
{% for error in row.non_field_specific_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
</ul>
</div>
</td>
{% for field in row.values %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% endfor %}
</tbody>
</table>
</ul>
{% endif %}
{% if import_job.import_status in import_job.success_statuses %}
<h2>{% trans "Totals" %}</h2>
<div>
{% for total, stat in import_job.result.totals.items %}
{{ total.title }}: <b>{{ stat }}</b><br>
{% endfor %}
</div>
<h2>
{% if import_job.import_status == "PARSED" %}
{% trans "These elements will be imported successfully" %}
Expand Down
Loading