django-forms-workflows 0.20.2__tar.gz → 0.20.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/PKG-INFO +1 -1
  2. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/submission_detail.html +50 -28
  3. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/views.py +47 -30
  4. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/pyproject.toml +1 -1
  5. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/CHANGELOG.md +0 -0
  6. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/LICENSE +0 -0
  7. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/README.md +0 -0
  8. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/__init__.py +0 -0
  9. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/admin.py +0 -0
  10. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/apps.py +0 -0
  11. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/context_processors.py +0 -0
  12. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/data_sources/__init__.py +0 -0
  13. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/data_sources/base.py +0 -0
  14. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/data_sources/database_source.py +0 -0
  15. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/data_sources/ldap_source.py +0 -0
  16. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/data_sources/user_source.py +0 -0
  17. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/email_backends/__init__.py +0 -0
  18. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/email_backends/gmail_api.py +0 -0
  19. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/form_builder_urls.py +0 -0
  20. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/form_builder_views.py +0 -0
  21. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/forms.py +0 -0
  22. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/__init__.py +0 -0
  23. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/api_handler.py +0 -0
  24. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/base.py +0 -0
  25. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/database_handler.py +0 -0
  26. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/email_handler.py +0 -0
  27. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/executor.py +0 -0
  28. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/file_handler.py +0 -0
  29. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/handlers/ldap_handler.py +0 -0
  30. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/ldap_backend.py +0 -0
  31. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/create_default_templates.py +0 -0
  32. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/pull_forms.py +0 -0
  33. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/push_forms.py +0 -0
  34. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/seed_farm_demo.py +0 -0
  35. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/seed_pcn_form.py +0 -0
  36. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/seed_prefill_sources.py +0 -0
  37. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/sync_ldap_profiles.py +0 -0
  38. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/management/commands/test_db_connection.py +0 -0
  39. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0001_initial.py +0 -0
  40. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0002_prefillsource_alter_formfield_prefill_source_and_more.py +0 -0
  41. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0003_postsubmissionaction.py +0 -0
  42. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0004_formtemplate.py +0 -0
  43. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0005_advanced_conditional_logic.py +0 -0
  44. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0006_workflowdefinition_visual_workflow_data_and_more.py +0 -0
  45. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0007_add_userprofile_ldap_enhancements.py +0 -0
  46. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0008_add_file_workflow_models.py +0 -0
  47. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0009_add_formfield_readonly.py +0 -0
  48. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0010_add_prefillsource_template_fields.py +0 -0
  49. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0011_postsubmissionaction_email_body_template_and_more.py +0 -0
  50. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0012_add_approval_step_fields.py +0 -0
  51. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0013_add_database_query_key.py +0 -0
  52. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0014_add_form_category.py +0 -0
  53. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0015_add_workflowstage_staged_approvals.py +0 -0
  54. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0016_add_pdf_generation.py +0 -0
  55. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0017_add_notification_batching.py +0 -0
  56. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0018_add_form_category_parent.py +0 -0
  57. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0019_add_ldap_group_profile.py +0 -0
  58. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0020_add_bulk_export_field.py +0 -0
  59. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0021_alter_pendingnotification_scheduled_for_and_more.py +0 -0
  60. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0022_add_bulk_pdf_export.py +0 -0
  61. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0023_add_performance_indexes.py +0 -0
  62. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0024_add_allow_resubmit.py +0 -0
  63. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0025_workflowstage_approve_label.py +0 -0
  64. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0026_alter_formfield_width.py +0 -0
  65. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0027_formsubmission_form_data_gin.py +0 -0
  66. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0028_workflowstagegroupconfig.py +0 -0
  67. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0029_formfield_workflow_stage_fk_drop_groupconfig.py +0 -0
  68. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0030_formfield_phone_type.py +0 -0
  69. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0031_sub_workflows.py +0 -0
  70. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0032_approved_pending_detached_sub_workflow.py +0 -0
  71. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0033_add_reject_parent_to_subworkflowdefinition.py +0 -0
  72. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0034_add_notificationlog.py +0 -0
  73. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0035_migrate_prefill_source_strings.py +0 -0
  74. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0036_add_workflowstage_auto_created.py +0 -0
  75. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0037_migrate_flat_workflows_to_staged.py +0 -0
  76. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0038_remove_legacy_prefill_source_and_approval_step.py +0 -0
  77. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0039_update_help_text.py +0 -0
  78. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0040_migrate_deprecated_features.py +0 -0
  79. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0041_remove_deprecated_fields.py +0 -0
  80. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0042_add_sub_workflow_section_label.py +0 -0
  81. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/0043_fix_form_data_decimal_encoding.py +0 -0
  82. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/migrations/__init__.py +0 -0
  83. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/models.py +0 -0
  84. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/signals.py +0 -0
  85. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/sso_backends.py +0 -0
  86. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/sso_urls.py +0 -0
  87. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/sso_views.py +0 -0
  88. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/static/django_forms_workflows/js/form-builder.js +0 -0
  89. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/static/django_forms_workflows/js/form-enhancements.js +0 -0
  90. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/static/django_forms_workflows/js/workflow-builder.js +0 -0
  91. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/sync_api.py +0 -0
  92. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/sync_views.py +0 -0
  93. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/tasks.py +0 -0
  94. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/form_builder.html +0 -0
  95. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/formdef_change_form.html +0 -0
  96. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/formdefinition/change_list.html +0 -0
  97. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/sync_import.html +0 -0
  98. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/sync_pull.html +0 -0
  99. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/sync_push.html +0 -0
  100. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/admin/django_forms_workflows/workflow_builder.html +0 -0
  101. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/_category_node.html +0 -0
  102. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/approval_inbox.html +0 -0
  103. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/approve.html +0 -0
  104. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/base.html +0 -0
  105. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/completed_approvals.html +0 -0
  106. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/form_categories.html +0 -0
  107. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/form_list.html +0 -0
  108. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/form_submit.html +0 -0
  109. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/my_submissions.html +0 -0
  110. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/resubmit_confirm.html +0 -0
  111. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/sso/login.html +0 -0
  112. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/sub_workflow_detail.html +0 -0
  113. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/submission_bulk_pdf.html +0 -0
  114. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/submission_pdf.html +0 -0
  115. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/django_forms_workflows/withdraw_confirm.html +0 -0
  116. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/approval_notification.html +0 -0
  117. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/approval_reminder.html +0 -0
  118. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/approval_request.html +0 -0
  119. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/email_styles.html +0 -0
  120. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/escalation_notification.html +0 -0
  121. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/notification_digest.html +0 -0
  122. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/rejection_notification.html +0 -0
  123. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/emails/submission_notification.html +0 -0
  124. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templates/registration/login.html +0 -0
  125. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templatetags/__init__.py +0 -0
  126. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/templatetags/forms_workflows_tags.py +0 -0
  127. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/urls.py +0 -0
  128. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/utils.py +0 -0
  129. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/workflow_builder_views.py +0 -0
  130. {django_forms_workflows-0.20.2 → django_forms_workflows-0.20.3}/django_forms_workflows/workflow_engine.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-forms-workflows
3
- Version: 0.20.2
3
+ Version: 0.20.3
4
4
  Summary: Enterprise-grade, database-driven form builder with approval workflows and external data integration
5
5
  License: LGPL-3.0-only
6
6
  License-File: LICENSE
@@ -241,52 +241,72 @@
241
241
  </div>
242
242
  {% endfor %}
243
243
 
244
- {% if sub_workflow_instances_merged %}
245
- {# ---- Merged sub-workflow table ---- #}
246
- <h5 class="mb-3 mt-4"><i class="bi bi-list-check"></i> {{ sub_wf_section_label|default:"Additional Approvals" }}</h5>
247
- <div class="card mb-3 border-secondary">
244
+ {% if sub_workflow_instance_stages %}
245
+ {# ---- Per-instance stage cards (like parent stages) ---- #}
246
+ {% for section in sub_workflow_instance_stages %}
247
+ <h5 class="mb-3 mt-4"><i class="bi bi-list-check"></i> {{ section.instance.label }}</h5>
248
+ {% for stage in section.stage_groups %}
249
+ <div class="card mb-3
250
+ {% if stage.rejected_count > 0 %}border-danger
251
+ {% elif stage.approved_count == stage.total_count and stage.total_count > 0 %}border-success
252
+ {% elif stage.approved_count > 0 %}border-primary
253
+ {% else %}border-secondary{% endif %}">
254
+ <div class="card-header d-flex justify-content-between align-items-center
255
+ {% if stage.rejected_count > 0 %}bg-danger text-white
256
+ {% elif stage.approved_count == stage.total_count and stage.total_count > 0 %}bg-success text-white
257
+ {% elif stage.approved_count > 0 %}bg-primary text-white
258
+ {% else %}bg-light text-muted{% endif %}">
259
+ <span>
260
+ <strong>Step {{ forloop.counter }}: {{ stage.name }}</strong>
261
+ {% if stage.approval_logic == "all" %}
262
+ <span class="badge bg-light text-dark ms-2" style="font-size:11px;">All must approve</span>
263
+ {% elif stage.approval_logic == "any" %}
264
+ <span class="badge bg-light text-dark ms-2" style="font-size:11px;">Any can approve</span>
265
+ {% else %}
266
+ <span class="badge bg-light text-dark ms-2" style="font-size:11px;">Sequential</span>
267
+ {% endif %}
268
+ </span>
269
+ <span class="badge bg-white
270
+ {% if stage.rejected_count > 0 %}text-danger
271
+ {% elif stage.approved_count == stage.total_count and stage.total_count > 0 %}text-success
272
+ {% else %}text-secondary{% endif %}">
273
+ {{ stage.approved_count }}/{{ stage.total_count }} approved
274
+ {% if stage.rejected_count > 0 %}&nbsp;· {{ stage.rejected_count }} rejected{% endif %}
275
+ </span>
276
+ </div>
248
277
  <div class="card-body p-0">
249
278
  <div class="table-responsive">
250
- <table class="table table-sm table-hover mb-0">
279
+ <table class="table table-sm mb-0">
251
280
  <thead class="table-light">
252
281
  <tr>
253
- <th>#</th>
254
- <th>Label</th>
255
282
  <th>Assigned To</th>
256
283
  <th>Status</th>
257
284
  <th>Completed By</th>
258
285
  <th>Completed At</th>
259
- <th></th>
286
+ <th>Comments</th>
260
287
  </tr>
261
288
  </thead>
262
289
  <tbody>
263
- {% for row in sub_workflow_instances_merged %}
290
+ {% for task in stage.tasks %}
264
291
  <tr>
265
- <td>{{ row.instance.index }}</td>
266
- <td>{{ row.instance.label }}</td>
267
292
  <td>
268
- {% if row.task %}
269
- {% if row.task.assigned_to %}
270
- {{ row.task.assigned_to.get_full_name|default:row.task.assigned_to.username }}
271
- {% elif row.task.assigned_group %}
272
- {{ row.task.assigned_group.name }}
273
- {% else %}-{% endif %}
293
+ {% if task.assigned_to %}
294
+ {{ task.assigned_to.get_full_name|default:task.assigned_to.username }}
295
+ {% elif task.assigned_group %}
296
+ {{ task.assigned_group.name }} <span class="text-muted">(Group)</span>
274
297
  {% else %}-{% endif %}
275
298
  </td>
276
299
  <td>
277
- {% if row.instance.status == 'approved' %}<span class="badge bg-success">Approved</span>
278
- {% elif row.instance.status == 'rejected' %}<span class="badge bg-danger">Rejected</span>
279
- {% elif row.instance.status == 'in_progress' %}<span class="badge bg-primary">In Progress</span>
280
- {% else %}<span class="badge bg-secondary">Pending</span>
300
+ {% if task.status == 'pending' %}<span class="badge bg-warning text-dark">Pending</span>
301
+ {% elif task.status == 'approved' %}<span class="badge bg-success">Approved</span>
302
+ {% elif task.status == 'rejected' %}<span class="badge bg-danger">Rejected</span>
303
+ {% elif task.status == 'expired' %}<span class="badge bg-secondary">Expired</span>
304
+ {% elif task.status == 'skipped' %}<span class="badge bg-secondary">Skipped</span>
281
305
  {% endif %}
282
306
  </td>
283
- <td>{% if row.task and row.task.completed_by %}{{ row.task.completed_by.get_full_name|default:row.task.completed_by.username }}{% else %}-{% endif %}</td>
284
- <td>{% if row.task and row.task.completed_at %}{{ row.task.completed_at|date:"Y-m-d H:i" }}{% else %}-{% endif %}</td>
285
- <td>
286
- <a href="{% url 'forms_workflows:sub_workflow_detail' row.instance.id %}" class="btn btn-sm btn-outline-secondary">
287
- <i class="bi bi-eye"></i> View
288
- </a>
289
- </td>
307
+ <td>{% if task.completed_by %}{{ task.completed_by.get_full_name|default:task.completed_by.username }}{% else %}-{% endif %}</td>
308
+ <td>{% if task.completed_at %}{{ task.completed_at|date:"Y-m-d H:i" }}{% else %}-{% endif %}</td>
309
+ <td>{{ task.comments|default:"-" }}</td>
290
310
  </tr>
291
311
  {% endfor %}
292
312
  </tbody>
@@ -294,6 +314,8 @@
294
314
  </div>
295
315
  </div>
296
316
  </div>
317
+ {% endfor %}
318
+ {% endfor %}
297
319
  {% endif %}
298
320
 
299
321
  {% else %}
@@ -604,14 +604,13 @@ def submission_detail(request, submission_id):
604
604
  for sg in sub_workflow_groups:
605
605
  sg["section_label"] = sg_name
606
606
 
607
- # Build merged sub-workflow instance rows that combine instance info
608
- # (index, label, status, created) with per-instance approval task info
609
- # (assigned_to, completed_by, completed_at) into a single table.
610
- sub_workflow_instances_merged = None
611
- sub_wf_section_label = None
607
+ # Build per-instance stage groups so each sub-workflow instance is
608
+ # rendered as its own section with stage cards (matching parent style).
609
+ sub_workflow_instance_stages = None
612
610
  sub_wfs = list(
613
611
  submission.sub_workflows.select_related("definition")
614
612
  .prefetch_related(
613
+ "approval_tasks__workflow_stage",
615
614
  "approval_tasks__assigned_to",
616
615
  "approval_tasks__assigned_group",
617
616
  "approval_tasks__completed_by",
@@ -619,34 +618,53 @@ def submission_detail(request, submission_id):
619
618
  .order_by("index")
620
619
  )
621
620
  if sub_wfs:
622
- swf_config = sub_wfs[0].definition if sub_wfs else None
623
- sub_wf_section_label = (
624
- (
625
- swf_config.section_label
626
- if swf_config and swf_config.section_label
627
- else None
628
- )
629
- or (swf_config.sub_workflow.form_definition.name if swf_config else None)
630
- or "Additional Approvals"
631
- )
632
- merged_rows = []
621
+ instance_sections = []
633
622
  for swf in sub_wfs:
634
- tasks = list(swf.approval_tasks.order_by("-completed_at", "id"))
635
- # Pick the most relevant task for display (completed or first pending)
636
- display_task = None
637
- for t in tasks:
638
- if t.status in ("approved", "rejected"):
639
- display_task = t
640
- break
641
- if not display_task and tasks:
642
- display_task = tasks[0]
643
- merged_rows.append(
623
+ tasks = list(
624
+ swf.approval_tasks.select_related("workflow_stage").order_by(
625
+ "stage_number", "id"
626
+ )
627
+ )
628
+ # Group tasks by workflow_stage (like parent stage_groups)
629
+ stage_map: dict = {}
630
+ for task in tasks:
631
+ stage_key = task.workflow_stage_id or f"flat_{task.stage_number}"
632
+ if stage_key not in stage_map:
633
+ stage_name = (
634
+ task.workflow_stage.name
635
+ if task.workflow_stage
636
+ else f"Step {task.stage_number or 1}"
637
+ )
638
+ approval_logic = (
639
+ task.workflow_stage.approval_logic
640
+ if task.workflow_stage
641
+ else "all"
642
+ )
643
+ stage_map[stage_key] = {
644
+ "number": task.stage_number or 0,
645
+ "name": stage_name,
646
+ "approval_logic": approval_logic,
647
+ "tasks": [],
648
+ "approved_count": 0,
649
+ "rejected_count": 0,
650
+ "total_count": 0,
651
+ }
652
+ stage_map[stage_key]["tasks"].append(task)
653
+ stage_map[stage_key]["total_count"] += 1
654
+ if task.status == "approved":
655
+ stage_map[stage_key]["approved_count"] += 1
656
+ elif task.status == "rejected":
657
+ stage_map[stage_key]["rejected_count"] += 1
658
+
659
+ instance_sections.append(
644
660
  {
645
661
  "instance": swf,
646
- "task": display_task,
662
+ "stage_groups": sorted(
663
+ stage_map.values(), key=lambda x: x["number"]
664
+ ),
647
665
  }
648
666
  )
649
- sub_workflow_instances_merged = merged_rows
667
+ sub_workflow_instance_stages = instance_sections
650
668
 
651
669
  # Resolve fresh presigned URLs for any file-upload fields
652
670
  form_data = _resolve_form_data_urls(submission.form_data)
@@ -678,8 +696,7 @@ def submission_detail(request, submission_id):
678
696
  "approval_tasks": approval_tasks,
679
697
  "stage_groups": stage_groups,
680
698
  "sub_workflow_groups": sub_workflow_groups,
681
- "sub_workflow_instances_merged": sub_workflow_instances_merged,
682
- "sub_wf_section_label": sub_wf_section_label,
699
+ "sub_workflow_instance_stages": sub_workflow_instance_stages,
683
700
  "form_data": form_data,
684
701
  "form_data_ordered": form_data_ordered,
685
702
  "approval_field_names": approval_field_names,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-forms-workflows"
3
- version = "0.20.2"
3
+ version = "0.20.3"
4
4
  description = "Enterprise-grade, database-driven form builder with approval workflows and external data integration"
5
5
  license = "LGPL-3.0-only"
6
6
  readme = "README.md"