Skip to content

Commit d6414e4

Browse files
matteiusclaude
andcommitted
fix: PDF page-break polish + drop redundant Stage column in inbox
PDF: - Removed :nth-child(even) zebra striping from both single and bulk PDFs. The alternating background looked odd next to half/third/quarter-width rows that render as one wide colspan row containing inline columns. - Added page-break-after: avoid / break-after: avoid on section dividers (.section-row, .step-section-header, .step-field-section-row) and on the .step-meta line so headers stay attached to the content they introduce. Added a dedicated .step-field-section-row class on the in-table divider <tr> so we don't depend on :has() selector support in WeasyPrint. Approval inbox: - Dropped the "Stage" column entirely. The Step label already carries the full context after the 0.71.0 naming standardisation ("Payment 1: Step 2: HR Processing" or "Step 2: HR Approval"), so the numeric stage column was redundant. Removed the <th>, the DataTables column spec, the "stage" key in the AJAX payload, and shifted default_sort_col down one to match. Bumps version to 0.72.2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 87226b3 commit d6414e4

6 files changed

Lines changed: 73 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.72.2] - 2026-04-16
11+
12+
### Changed
13+
- **PDF exports no longer zebra-stripe data rows.** The alternating
14+
`:nth-child(even)` tint looked inconsistent when combined with
15+
half / third / quarter-width rows (which render as a single wide
16+
colspan row containing inline columns). Both
17+
`submission_pdf.html` and `submission_bulk_pdf.html` now use a
18+
uniform white data-row background.
19+
- **Approval inbox: dropped the redundant "Stage" column.** The Step
20+
label now carries the full context (`"Payment 1: Step 2: HR Processing"`
21+
or `"Step 2: HR Approval"`), so a separate numeric stage column is no
22+
longer useful. Removed the `<th>`, the DataTables column spec, the
23+
`"stage"` key from the AJAX payload, and shifted the default sort
24+
column index down one.
25+
26+
### Fixed
27+
- **PDF page breaks keep section headers attached to their content.**
28+
Section dividers (`.section-row`, `.step-section-header`,
29+
`.step-field-section-row`) and the per-step meta line (`.step-meta`)
30+
now set `page-break-after: avoid` / `break-after: avoid` so a
31+
section header no longer orphans at the bottom of one page with its
32+
fields starting on the next. Applies to both single-submission and
33+
bulk PDFs.
34+
1035
## [0.72.1] - 2026-04-16
1136

1237
### Fixed

django_forms_workflows/templates/django_forms_workflows/approval_inbox.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,6 @@ <h5 class="modal-title fw-bold" id="bulkPdfModeModalLabel">
253253
<th>Actions</th>
254254
<th>Form</th>
255255
<th>Submitter</th>
256-
<th>Stage</th>
257256
<th>Step</th>
258257
<th>Assigned</th>
259258
<th>Submitted</th>
@@ -346,7 +345,6 @@ <h5 class="modal-title fw-bold" id="bulkPdfModeModalLabel">
346345
{ data: 'actions', name: '', orderable: false },
347346
{ data: 'form', name: 'submission__form_definition__name' },
348347
{ data: 'submitter', name: 'submission__submitter__last_name' },
349-
{ data: 'stage', name: 'stage_number' },
350348
{ data: 'step_num', name: 'workflow_stage__name' },
351349
{ data: 'assigned', name: 'assigned_group__name' },
352350
{ data: 'submitted_at', name: 'submission__submitted_at' },

django_forms_workflows/templates/django_forms_workflows/submission_bulk_pdf.html

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,20 @@
5151
.data-table th { background-color: #f0f0f0; font-weight: bold; font-size: 8pt; color: #333; border: 1px solid #d0d0d0; padding: 3pt 6pt; text-align: left; vertical-align: top; }
5252
.data-table td { font-size: 9pt; border: 1px solid #d0d0d0; padding: 3pt 6pt; vertical-align: top; }
5353
.data-table tr { page-break-inside: avoid; break-inside: avoid; }
54-
.data-table tr:nth-child(even) th,
55-
.data-table tr:nth-child(even) td { background-color: #f9f9f9; }
5654
.section-row td { background-color: #e8f0f7 !important; color: #1a3a52; font-weight: bold; font-size: 8pt; letter-spacing: 0.3pt; text-transform: uppercase; padding: 4pt 6pt; border: 1px solid #b8ccd8; }
57-
.step-section-header { background-color: #1a3a52; color: #fff; font-weight: bold; font-size: 9pt; padding: 4pt 6pt; margin-top: 10pt; border: 1px solid #0f2538; }
58-
.step-meta { font-size: 7.5pt; color: #555; margin: 2pt 0 4pt 0; }
55+
/* Keep each section header attached to the content that follows it. */
56+
.section-row { page-break-after: avoid; break-after: avoid; page-break-inside: avoid; break-inside: avoid; }
57+
.step-section-header {
58+
background-color: #1a3a52; color: #fff; font-weight: bold; font-size: 9pt;
59+
padding: 4pt 6pt; margin-top: 10pt; border: 1px solid #0f2538;
60+
page-break-after: avoid; break-after: avoid;
61+
page-break-inside: avoid; break-inside: avoid;
62+
}
63+
.step-meta {
64+
font-size: 7.5pt; color: #555; margin: 2pt 0 4pt 0;
65+
page-break-before: avoid; break-before: avoid;
66+
page-break-after: avoid; break-after: avoid;
67+
}
5968
</style>
6069
</head>
6170
<body>

django_forms_workflows/templates/django_forms_workflows/submission_pdf.html

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,10 @@
106106
break-inside: avoid;
107107
}
108108

109-
/* Alternating row tint — WeasyPrint supports :nth-child fully */
110-
.data-table tr:nth-child(even) th,
111-
.data-table tr:nth-child(even) td { background-color: #f9f9f9; }
112-
113-
/* Section rows always keep their own colour regardless of position */
109+
/* Section rows always keep their own colour regardless of position.
110+
Also keep each section header with the content that follows it —
111+
prevents the ugly case where a header renders at the bottom of one
112+
page and its fields start on the next. */
114113
.section-row td {
115114
background-color: #e8f0f7 !important;
116115
color: #1a3a52;
@@ -121,6 +120,12 @@
121120
padding: 4pt 6pt;
122121
border: 1px solid #b8ccd8;
123122
}
123+
.section-row {
124+
page-break-after: avoid;
125+
break-after: avoid;
126+
page-break-inside: avoid;
127+
break-inside: avoid;
128+
}
124129

125130
/* Approval-step section header */
126131
.step-section-header {
@@ -134,6 +139,11 @@
134139
display: table;
135140
width: 100%;
136141
box-sizing: border-box;
142+
/* Keep the step header with its meta line / following table */
143+
page-break-after: avoid;
144+
break-after: avoid;
145+
page-break-inside: avoid;
146+
break-inside: avoid;
137147
}
138148
.step-section-header .step-name-cell { display: table-cell; vertical-align: middle; }
139149
.step-section-header .step-badge-cell {
@@ -152,6 +162,22 @@
152162
font-size: 9pt;
153163
padding: 4pt 8pt;
154164
}
165+
/* Section divider row inside the step table: stay attached to the
166+
following field row rather than orphaning at the bottom of a page. */
167+
tr.step-field-section-row {
168+
page-break-after: avoid;
169+
break-after: avoid;
170+
page-break-inside: avoid;
171+
break-inside: avoid;
172+
}
173+
/* Meta line (completed by / date / comment) belongs with its header
174+
and the following table. */
175+
.step-meta {
176+
page-break-before: avoid;
177+
break-before: avoid;
178+
page-break-after: avoid;
179+
break-after: avoid;
180+
}
155181
.step-badge {
156182
display: inline-block;
157183
padding: 2pt 7pt;
@@ -300,7 +326,7 @@ <h3 style="margin-top: 20px;">Attachments</h3>
300326
<tbody>
301327
{% for row in section.fields %}
302328
{% if row.type == 'section' %}
303-
<tr>
329+
<tr class="step-field-section-row">
304330
<td colspan="4" class="step-field-section">{{ row.label }}</td>
305331
</tr>
306332
{% elif row.type == 'display_text' %}

django_forms_workflows/views.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,8 +1456,8 @@ def approval_inbox(request):
14561456
# Compute default sort column index for DataTables (submitted_at)
14571457
_exp_off = 1 if (any_exportable or any_pdf_exportable) else 0
14581458
_cat_off = 0 if category_slug else 1
1459-
# columns: [checkbox?] [category?] actions form submitter stage step_num assigned submitted_at
1460-
default_sort_col = _exp_off + _cat_off + 1 + 5 # index of submitted_at
1459+
# columns: [checkbox?] [category?] actions form submitter step_num assigned submitted_at
1460+
default_sort_col = _exp_off + _cat_off + 1 + 4 # index of submitted_at
14611461

14621462
return render(
14631463
request,
@@ -4215,7 +4215,6 @@ def approval_inbox_ajax(request):
42154215
"submitter": escape(
42164216
sub.submitter.get_full_name() or sub.submitter.username
42174217
),
4218-
"stage": f"Stage {task.stage_number}" if task.stage_number else "—",
42194218
"step_num": escape(stage_name),
42204219
"assigned": escape(
42214220
task.assigned_group.name

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "django-forms-workflows"
3-
version = "0.72.1"
3+
version = "0.72.2"
44
description = "Enterprise-grade, database-driven form builder with approval workflows and external data integration"
55
license = "LGPL-3.0-only"
66
readme = "README.md"

0 commit comments

Comments
 (0)