django-forms-workflows 0.76.6__tar.gz → 0.77.0__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 (229) hide show
  1. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/CHANGELOG.md +72 -4
  2. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/PKG-INFO +1 -1
  3. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/form_builder_views.py +0 -14
  4. django_forms_workflows-0.77.0/django_forms_workflows/static/django_forms_workflows/js/workflow-builder-api.js +184 -0
  5. django_forms_workflows-0.77.0/django_forms_workflows/static/django_forms_workflows/js/workflow-builder-store.js +56 -0
  6. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/workflow-builder.js +31 -184
  7. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/tasks.py +75 -11
  8. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/pyproject.toml +1 -1
  9. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/LICENSE +0 -0
  10. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/README.md +0 -0
  11. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/__init__.py +0 -0
  12. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/admin.py +0 -0
  13. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/api_urls.py +0 -0
  14. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/api_views.py +0 -0
  15. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/apps.py +0 -0
  16. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/callback_registry.py +0 -0
  17. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/conditions.py +0 -0
  18. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/context_processors.py +0 -0
  19. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/__init__.py +0 -0
  20. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/base.py +0 -0
  21. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/database_source.py +0 -0
  22. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/ldap_source.py +0 -0
  23. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/user_source.py +0 -0
  24. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/diff_views.py +0 -0
  25. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/email_backends/__init__.py +0 -0
  26. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/email_backends/gmail_api.py +0 -0
  27. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/form_builder_urls.py +0 -0
  28. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/forms.py +0 -0
  29. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/__init__.py +0 -0
  30. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/api_handler.py +0 -0
  31. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/base.py +0 -0
  32. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/database_handler.py +0 -0
  33. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/email_handler.py +0 -0
  34. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/executor.py +0 -0
  35. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/file_handler.py +0 -0
  36. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/ldap_handler.py +0 -0
  37. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/history.py +0 -0
  38. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/ldap_backend.py +0 -0
  39. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/create_default_templates.py +0 -0
  40. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/pull_forms.py +0 -0
  41. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/push_forms.py +0 -0
  42. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/seed_farm_demo.py +0 -0
  43. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/seed_pcn_form.py +0 -0
  44. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/seed_prefill_sources.py +0 -0
  45. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/sync_ldap_profiles.py +0 -0
  46. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/sync_ldap_users.py +0 -0
  47. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/test_db_connection.py +0 -0
  48. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0001_initial.py +0 -0
  49. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0002_prefillsource_alter_formfield_prefill_source_and_more.py +0 -0
  50. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0003_postsubmissionaction.py +0 -0
  51. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0004_formtemplate.py +0 -0
  52. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0005_advanced_conditional_logic.py +0 -0
  53. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0006_workflowdefinition_visual_workflow_data_and_more.py +0 -0
  54. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0007_add_userprofile_ldap_enhancements.py +0 -0
  55. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0008_add_file_workflow_models.py +0 -0
  56. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0009_add_formfield_readonly.py +0 -0
  57. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0010_add_prefillsource_template_fields.py +0 -0
  58. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0011_postsubmissionaction_email_body_template_and_more.py +0 -0
  59. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0012_add_approval_step_fields.py +0 -0
  60. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0013_add_database_query_key.py +0 -0
  61. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0014_add_form_category.py +0 -0
  62. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0015_add_workflowstage_staged_approvals.py +0 -0
  63. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0016_add_pdf_generation.py +0 -0
  64. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0017_add_notification_batching.py +0 -0
  65. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0018_add_form_category_parent.py +0 -0
  66. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0019_add_ldap_group_profile.py +0 -0
  67. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0020_add_bulk_export_field.py +0 -0
  68. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0021_alter_pendingnotification_scheduled_for_and_more.py +0 -0
  69. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0022_add_bulk_pdf_export.py +0 -0
  70. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0023_add_performance_indexes.py +0 -0
  71. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0024_add_allow_resubmit.py +0 -0
  72. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0025_workflowstage_approve_label.py +0 -0
  73. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0026_alter_formfield_width.py +0 -0
  74. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0027_formsubmission_form_data_gin.py +0 -0
  75. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0028_workflowstagegroupconfig.py +0 -0
  76. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0029_formfield_workflow_stage_fk_drop_groupconfig.py +0 -0
  77. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0030_formfield_phone_type.py +0 -0
  78. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0031_sub_workflows.py +0 -0
  79. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0032_approved_pending_detached_sub_workflow.py +0 -0
  80. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0033_add_reject_parent_to_subworkflowdefinition.py +0 -0
  81. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0034_add_notificationlog.py +0 -0
  82. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0035_migrate_prefill_source_strings.py +0 -0
  83. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0036_add_workflowstage_auto_created.py +0 -0
  84. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0037_migrate_flat_workflows_to_staged.py +0 -0
  85. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0038_remove_legacy_prefill_source_and_approval_step.py +0 -0
  86. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0039_update_help_text.py +0 -0
  87. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0040_migrate_deprecated_features.py +0 -0
  88. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0041_remove_deprecated_fields.py +0 -0
  89. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0042_add_sub_workflow_section_label.py +0 -0
  90. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0043_fix_form_data_decimal_encoding.py +0 -0
  91. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0044_remove_subworkflowinstance_label.py +0 -0
  92. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0045_stageapprovalgroup_workflow_name_label.py +0 -0
  93. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0046_workflow_definition_one_to_many.py +0 -0
  94. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0047_add_hide_approval_history.py +0 -0
  95. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0048_workflowdefinition_trigger_conditions_and_more.py +0 -0
  96. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0049_formfield_multifile_type.py +0 -0
  97. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0050_workflowdefinition_collapse_parallel_stages.py +0 -0
  98. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0051_formdefinition_is_listed.py +0 -0
  99. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0052_dynamic_assignee_and_form_field_notifications.py +0 -0
  100. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0053_stageformfieldnotification_static_emails.py +0 -0
  101. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0054_rename_approved_pending_to_pending_approval.py +0 -0
  102. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0055_add_send_back.py +0 -0
  103. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0056_calculated_formula_spreadsheet.py +0 -0
  104. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0057_add_currency_field_type.py +0 -0
  105. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0058_rename_assignee_email_field_add_lookup_type.py +0 -0
  106. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0059_add_multiselect_list_field_type.py +0 -0
  107. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0060_alter_workflowstage_assignee_lookup_type_helptext.py +0 -0
  108. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0061_add_country_us_state_field_types.py +0 -0
  109. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0062_add_batch_import_to_formdefinition.py +0 -0
  110. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0063_formdefinition_api_enabled_apitoken.py +0 -0
  111. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0064_add_reviewer_groups.py +0 -0
  112. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0065_workflownotification.py +0 -0
  113. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0066_add_notify_submitter_to_workflownotification.py +0 -0
  114. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0067_migrate_legacy_notify_flags.py +0 -0
  115. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0068_drop_legacy_notify_fields.py +0 -0
  116. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0069_add_signature_field_type.py +0 -0
  117. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0070_workflowstage_allow_edit_form_data.py +0 -0
  118. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0071_alter_pendingnotification_notification_type.py +0 -0
  119. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0072_add_change_history.py +0 -0
  120. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0073_add_stage_notify_assignee_on_final_decision.py +0 -0
  121. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0074_add_notification_rule.py +0 -0
  122. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0075_migrate_to_notification_rules.py +0 -0
  123. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0076_update_notification_event_choices.py +0 -0
  124. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0077_drop_legacy_notification_models.py +0 -0
  125. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0078_allow_anonymous_submissions.py +0 -0
  126. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0079_webhookendpoint_webhookdeliverylog.py +0 -0
  127. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0080_add_rating_matrix_address_slider_fields_and_form_controls.py +0 -0
  128. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0081_add_success_page_fields.py +0 -0
  129. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0082_add_document_template_model.py +0 -0
  130. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0083_workflowdefinition_start_trigger.py +0 -0
  131. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0084_add_shared_option_list.py +0 -0
  132. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0085_add_payment_system.py +0 -0
  133. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0086_add_embed_enabled.py +0 -0
  134. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0087_notificationrule_use_triggering_stage.py +0 -0
  135. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0088_notificationrule_body_template_and_events.py +0 -0
  136. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0089_workflowstage_hide_comment_field.py +0 -0
  137. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0090_alter_stageapprovalgroup_options_and_more.py +0 -0
  138. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0091_add_uuid_fields.py +0 -0
  139. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0092_add_user_notification_preference.py +0 -0
  140. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0093_normalize_conditional_operators.py +0 -0
  141. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0094_formfield_show_help_text_in_detail.py +0 -0
  142. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0095_notificationrule_cc_fields.py +0 -0
  143. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0096_notificationlog_cc_bcc_emails.py +0 -0
  144. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0097_notificationlog_delivery_reconciliation.py +0 -0
  145. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/__init__.py +0 -0
  146. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/models.py +0 -0
  147. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/__init__.py +0 -0
  148. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/base.py +0 -0
  149. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/registry.py +0 -0
  150. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/stripe_provider.py +0 -0
  151. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/views.py +0 -0
  152. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/reporting_views.py +0 -0
  153. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/signals.py +0 -0
  154. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sso_backends.py +0 -0
  155. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sso_urls.py +0 -0
  156. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sso_views.py +0 -0
  157. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/api/swagger-ui-bundle.js +0 -0
  158. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/api/swagger-ui.css +0 -0
  159. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/css/forms.css +0 -0
  160. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/admin_notification_rule_stage_filter.js +0 -0
  161. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/dfw-embed.js +0 -0
  162. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-builder-api.js +0 -0
  163. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-builder-canvas.js +0 -0
  164. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-builder-history.js +0 -0
  165. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-builder-property-editor.js +0 -0
  166. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-builder-store.js +0 -0
  167. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-builder.js +0 -0
  168. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/form-enhancements.js +0 -0
  169. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/payment-stripe.js +0 -0
  170. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/js/signature-pad.js +0 -0
  171. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sync_api.py +0 -0
  172. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sync_views.py +0 -0
  173. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/_sync_diff.html +0 -0
  174. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/diff_forms.html +0 -0
  175. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/form_builder.html +0 -0
  176. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/formdef_change_form.html +0 -0
  177. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/formdefinition/change_list.html +0 -0
  178. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/sync_import.html +0 -0
  179. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/sync_pull.html +0 -0
  180. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/sync_push.html +0 -0
  181. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/admin/django_forms_workflows/workflow_builder.html +0 -0
  182. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/_category_node.html +0 -0
  183. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/_field_value.html +0 -0
  184. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/_form_data_rows.html +0 -0
  185. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/analytics_dashboard.html +0 -0
  186. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/api/docs.html +0 -0
  187. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/approval_inbox.html +0 -0
  188. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/approve.html +0 -0
  189. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/base.html +0 -0
  190. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/batch_import_result.html +0 -0
  191. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/completed_approvals.html +0 -0
  192. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/discard_draft_confirm.html +0 -0
  193. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/embed_base.html +0 -0
  194. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/embed_success.html +0 -0
  195. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_categories.html +0 -0
  196. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_embed.html +0 -0
  197. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_list.html +0 -0
  198. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_submit.html +0 -0
  199. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/my_submissions.html +0 -0
  200. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/notification_preferences.html +0 -0
  201. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/payment_collect.html +0 -0
  202. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/payment_error.html +0 -0
  203. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/public_submission_confirmation.html +0 -0
  204. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/rate_limited.html +0 -0
  205. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/reassign_task.html +0 -0
  206. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/resubmit_confirm.html +0 -0
  207. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/sso/login.html +0 -0
  208. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/sub_workflow_detail.html +0 -0
  209. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_bulk_pdf.html +0 -0
  210. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_detail.html +0 -0
  211. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_pdf.html +0 -0
  212. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_success.html +0 -0
  213. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/withdraw_confirm.html +0 -0
  214. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/approval_notification.html +0 -0
  215. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/approval_reminder.html +0 -0
  216. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/approval_request.html +0 -0
  217. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/email_styles.html +0 -0
  218. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/escalation_notification.html +0 -0
  219. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/notification_digest.html +0 -0
  220. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/rejection_notification.html +0 -0
  221. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/submission_notification.html +0 -0
  222. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/registration/login.html +0 -0
  223. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templatetags/__init__.py +0 -0
  224. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templatetags/forms_workflows_tags.py +0 -0
  225. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/urls.py +0 -0
  226. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/utils.py +0 -0
  227. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/views.py +0 -0
  228. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/workflow_builder_views.py +0 -0
  229. {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/workflow_engine.py +0 -0
@@ -7,15 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.77.0] - 2026-08-17
11
+
12
+ Some entries below are marked *(shipped in 0.76.x)* — they describe changes that
13
+ were released earlier but never moved out of `[Unreleased]`, so they are recorded
14
+ here rather than lost.
15
+
10
16
  ### Changed
17
+ - **`@staff_member_required` dropped from the form builder's views.**
18
+ All 13 views in `form_builder_views.py` no longer carry the decorator.
19
+ Admin URLs remain gated because `FormDefinitionAdmin.get_urls()` wraps every view in
20
+ `self.admin_site.admin_view(...)`, which enforces `is_staff`.
21
+ Any non-admin URL registrations (e.g. `form_builder_urls.py`) must now apply
22
+ their own staff gating if needed — no change for admin routes. A new
23
+ `test_..._requires_staff` test per view confirms `admin_view()` alone still
24
+ gates non-staff access.
25
+ - **Workflow builder state moved behind a store.** `createWorkflowBuilderStore()`
26
+ is now the single owner of builder state, and `workflow-builder-api.js` was
27
+ extracted out of `workflow-builder.js`, so node/connection mutations go through
28
+ the store's setters instead of touching module-level state directly.
29
+ - **Dependency bumps.** The pip group (15 updates) and `postcss`, via Dependabot.
11
30
  - **Form builder save logic factored into a standalone helper.**
31
+ *(shipped in 0.76.1)*
12
32
  `form_builder_save`'s create/update logic for `FormDefinition` and its
13
33
  `FormField`s now lives in `save_form_definition_from_builder_data()`,
14
34
  mirroring the existing `convert_visual_to_workflow` split already used by
15
35
  the workflow builder. Makes the logic callable (and unit-testable)
16
36
  independently of the `@staff_member_required`-decorated HTTP view — no
17
37
  behavior or API change.
18
- - **Notification rules identify their workflow in the admin.** The standalone
38
+ - **Notification rules identify their workflow in the admin.** *(shipped in
39
+ 0.76.0)* The standalone
19
40
  `NotificationRule` list rendered only `workflow.form_definition.name`, so a
20
41
  rule on a parent workflow and a rule on its sub-workflow both displayed the
21
42
  same form name — and for workflow-level rules the Stage column reads
@@ -28,7 +49,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
28
49
  label so every FK picker, autocomplete result, and log entry disambiguates.
29
50
 
30
51
  ### Fixed
31
- - **Browser value suggestions restored on generic text fields.** The
52
+ - **A failing notification rule no longer silences the rest of its event.**
53
+ `send_notification_rules` ran every matching rule in one unguarded loop, so a
54
+ single exception aborted the task and every remaining rule with it — and left
55
+ nothing behind, because `NotificationLog` rows are only written by the send
56
+ helpers further down. Each rule's body moved into `_apply_rule()` and the loop
57
+ now isolates it: a raising rule is logged with a traceback, records a
58
+ `status="failed"` `NotificationLog` row naming the rule and exception, and the
59
+ next rule still runs. This is the amplifier that turned the file-upload
60
+ `TypeError` below into a total blackout rather than one missing email.
61
+ - **`ApprovalTask.reminder_sent_at` now reflects a reminder that was actually
62
+ dispatched.** `check_approval_deadlines` stamped it immediately after
63
+ `send_notification_rules.delay(...)`, but enqueuing is not sending — a task
64
+ lost in the broker or killed mid-flight left the reminder permanently recorded
65
+ as sent and never retried, with no log row to contradict it. The stamp moved
66
+ into `send_notification_rules`, applied once the dispatch runs to completion.
67
+ Completing with zero recipients still stamps, so a workflow with no reminder
68
+ rule doesn't re-dispatch on every sweep; a crash leaves it unset so the next
69
+ sweep retries, and duplicate sends are absorbed by the existing `already_sent`
70
+ idempotency guard. **Behaviour change:** reminders are now retried until a
71
+ dispatch completes, where previously they were attempted exactly once.
72
+ - **File-upload fields no longer silence every notification for a submission.**
73
+ Subject answer-piping (added in 0.54.0) stringified each `form_data` value with
74
+ `", ".join(v) if isinstance(v, list) else str(v)`. A multi-file upload field
75
+ stores a *list of dicts*, so the join raised
76
+ `TypeError: sequence item 0: expected str instance, dict found`. That happens
77
+ while building `_pipe_vars` — before any email is sent and before any
78
+ `NotificationLog` row is written — so `send_notification_rules` died with no
79
+ email, no log row, and not even a `status="failed"` record. `@shared_task`
80
+ carries no autoretry, so the notification was lost permanently, and since
81
+ `form_data` is identical for every event, *all* events for that submission
82
+ (`submission_received`, `approval_request`, `approval_reminder`, …) failed the
83
+ same way — a silent, total blackout. The blackout was invisible from the data,
84
+ because `check_approval_deadlines` stamped `ApprovalTask.reminder_sent_at` right
85
+ after a successful `.delay()`, so reminders looked sent while the worker crash
86
+ happened later (see the `reminder_sent_at` entry above, which closes that gap).
87
+ Values are now stringified by `_pipe_value()`, which renders file dicts
88
+ as their filename (matching `_export_xlsx`), recurses into lists, coerces
89
+ non-string members, and never raises. The piping token itself was never the
90
+ trigger — any file field present in `form_data` was enough, whether or not the
91
+ subject referenced it.
92
+ - **Workflow builder store-wiring fixes.** `createNode` / `createStartNode` and
93
+ `finishConnection` bypassed the store's setter and mutated state directly, and
94
+ the checkbox change handler stored the raw `"on"` string instead of a boolean.
95
+ Regression coverage was added alongside the fixes.
96
+ - **Browser value suggestions restored on generic text fields.** *(shipped in
97
+ 0.76.3)* The
32
98
  password-manager opt-out added in 0.74.15 set `autocomplete="off"` alongside
33
99
  the `data-1p-ignore` / `data-lpignore` / `data-bwignore` / `data-form-type`
34
100
  attributes on every field type in `_PM_OPT_OUT_FIELD_TYPES`. Those `data-*`
@@ -39,7 +105,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
39
105
  native suggestions work again while password-manager popovers stay
40
106
  suppressed. Fields with their own suggestion UI (LDAP lookup) are unaffected
41
107
  — `ldap-lookup.js` sets `autocomplete="off"` on them directly.
42
- - **Diff and sync summaries no longer ignore sub-workflows.** `_build_summary`
108
+ - **Diff and sync summaries no longer ignore sub-workflows.** *(shipped in
109
+ 0.76.3)* `_build_summary`
43
110
  read only the `"workflow"` key, but `serialize_form` stores the first
44
111
  workflow there and every other one under `"additional_workflows"`. A
45
112
  sub-workflow's stages, settings, and notification rules were therefore
@@ -1890,7 +1957,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1890
1957
  - psycopg2-binary >= 2.9 (for PostgreSQL)
1891
1958
  - mysqlclient >= 2.2 (for MySQL)
1892
1959
 
1893
- [Unreleased]: https://github.com/opensensor/django-forms-workflows/compare/v0.2.2...HEAD
1960
+ [Unreleased]: https://github.com/opensensor/django-forms-workflows/compare/v0.77.0...HEAD
1961
+ [0.77.0]: https://github.com/opensensor/django-forms-workflows/compare/v0.76.6...v0.77.0
1894
1962
  [0.2.2]: https://github.com/opensensor/django-forms-workflows/compare/v0.2.1...v0.2.2
1895
1963
  [0.2.1]: https://github.com/opensensor/django-forms-workflows/compare/v0.2.0...v0.2.1
1896
1964
  [0.2.0]: https://github.com/opensensor/django-forms-workflows/compare/v0.1.0...v0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-forms-workflows
3
- Version: 0.76.6
3
+ Version: 0.77.0
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
@@ -9,7 +9,6 @@ import json
9
9
  import logging
10
10
  import uuid
11
11
 
12
- from django.contrib.admin.views.decorators import staff_member_required
13
12
  from django.db import transaction
14
13
  from django.http import JsonResponse
15
14
  from django.shortcuts import get_object_or_404, render
@@ -31,7 +30,6 @@ from .models import (
31
30
  logger = logging.getLogger(__name__)
32
31
 
33
32
 
34
- @staff_member_required
35
33
  @require_GET
36
34
  def form_builder_templates(request):
37
35
  """
@@ -64,7 +62,6 @@ def form_builder_templates(request):
64
62
  )
65
63
 
66
64
 
67
- @staff_member_required
68
65
  @require_GET
69
66
  def form_builder_load_template(request, template_id):
70
67
  """
@@ -85,7 +82,6 @@ def form_builder_load_template(request, template_id):
85
82
  )
86
83
 
87
84
 
88
- @staff_member_required
89
85
  @require_POST
90
86
  def form_builder_clone(request, form_id):
91
87
  """
@@ -228,7 +224,6 @@ def form_builder_clone(request, form_id):
228
224
  )
229
225
 
230
226
 
231
- @staff_member_required
232
227
  @require_GET
233
228
  def form_builder_view(request, form_id=None):
234
229
  """
@@ -273,7 +268,6 @@ def form_builder_view(request, form_id=None):
273
268
  return render(request, "admin/django_forms_workflows/form_builder.html", context)
274
269
 
275
270
 
276
- @staff_member_required
277
271
  @require_GET
278
272
  def form_builder_load(request, form_id):
279
273
  """
@@ -358,7 +352,6 @@ def form_builder_load(request, form_id):
358
352
  return JsonResponse(form_data)
359
353
 
360
354
 
361
- @staff_member_required
362
355
  @require_POST
363
356
  def form_builder_save(request):
364
357
  """
@@ -610,7 +603,6 @@ def save_form_definition_from_builder_data(data, user, form_definition=None):
610
603
  return form_definition, field_id_mapping
611
604
 
612
605
 
613
- @staff_member_required
614
606
  @require_POST
615
607
  def form_builder_preview(request):
616
608
  """
@@ -771,7 +763,6 @@ def form_builder_preview(request):
771
763
  # ---------------------------------------------------------------------------
772
764
 
773
765
 
774
- @staff_member_required
775
766
  @require_GET
776
767
  def document_template_list(request, form_id):
777
768
  """List document templates for a form."""
@@ -797,7 +788,6 @@ def document_template_list(request, form_id):
797
788
  )
798
789
 
799
790
 
800
- @staff_member_required
801
791
  @require_POST
802
792
  def document_template_save(request, form_id):
803
793
  """Create or update a document template."""
@@ -856,7 +846,6 @@ def document_template_save(request, form_id):
856
846
  )
857
847
 
858
848
 
859
- @staff_member_required
860
849
  @require_POST
861
850
  def document_template_delete(request, form_id, template_id):
862
851
  """Delete a document template."""
@@ -872,7 +861,6 @@ def document_template_delete(request, form_id, template_id):
872
861
  # ---------------------------------------------------------------------------
873
862
 
874
863
 
875
- @staff_member_required
876
864
  @require_GET
877
865
  def shared_option_list_api(request):
878
866
  """List all shared option lists (for form builder dropdowns)."""
@@ -893,7 +881,6 @@ def shared_option_list_api(request):
893
881
  )
894
882
 
895
883
 
896
- @staff_member_required
897
884
  @require_POST
898
885
  def shared_option_list_save(request):
899
886
  """Create or update a shared option list."""
@@ -936,7 +923,6 @@ def shared_option_list_save(request):
936
923
  )
937
924
 
938
925
 
939
- @staff_member_required
940
926
  @require_POST
941
927
  def shared_option_list_delete(request, list_id):
942
928
  """Delete a shared option list."""
@@ -0,0 +1,184 @@
1
+ /**
2
+ * API client for the Workflow Builder: loading/saving the workflow
3
+ * definition, plus save-status and dirty-tracking bookkeeping around those
4
+ * two calls.
5
+ *
6
+ * Mixed onto WorkflowBuilder.prototype in workflow-builder.js
7
+ * (Object.assign), not a standalone class of its own - these methods read/
8
+ * write `this.nodes`/`this.connections`/`this.config` directly, plus call
9
+ * back into validation/canvas methods (refreshValidationState/selectNode/
10
+ * initializeNodeStackOrder/layoutNeedsNormalization/autoArrangeNodes/
11
+ * setBuilderMessage) that still live on the single WorkflowBuilder
12
+ * instance. Mirrors form-builder-api.js's shape/scope.
13
+ */
14
+ export const apiMethods = {
15
+ setSaveStatus(text, tone = 'neutral') {
16
+ const status = document.getElementById('saveStatus');
17
+ if (!status) return;
18
+ status.textContent = text;
19
+ status.dataset.tone = tone;
20
+ },
21
+
22
+ getWorkflowSnapshot() {
23
+ return this.store.snapshot();
24
+ },
25
+
26
+ syncSavedWorkflowSnapshot() {
27
+ this.lastSavedWorkflowSnapshot = this.getWorkflowSnapshot();
28
+ this.updateDirtyState();
29
+ },
30
+
31
+ updateDirtyState() {
32
+ this.isDirty = this.lastSavedWorkflowSnapshot !== null
33
+ && this.getWorkflowSnapshot() !== this.lastSavedWorkflowSnapshot;
34
+ this.updateDirtyIndicator();
35
+ },
36
+
37
+ updateDirtyIndicator() {
38
+ const badge = document.getElementById('dirtyIndicator');
39
+ if (badge) {
40
+ badge.hidden = !this.isDirty;
41
+ }
42
+
43
+ if (!this.isSaving) {
44
+ if (this.isDirty) {
45
+ this.setSaveStatus('Unsaved changes', 'warning');
46
+ } else {
47
+ this.setSaveStatus('Ready', 'neutral');
48
+ }
49
+ }
50
+ },
51
+
52
+ async loadWorkflow() {
53
+ try {
54
+ console.log('Loading workflow from:', this.config.apiUrls.load);
55
+ const response = await fetch(this.config.apiUrls.load);
56
+ const data = await response.json();
57
+
58
+ console.log('Workflow data received:', data);
59
+
60
+ if (data.success) {
61
+ this.nodes = data.workflow.nodes || [];
62
+ this.connections = data.workflow.connections || [];
63
+ this.fields = data.fields || [];
64
+ this.groups = data.groups || [];
65
+ this.forms = data.forms || [];
66
+ this.workflowTargets = data.workflow_targets || [];
67
+
68
+ console.log('Loaded nodes:', this.nodes);
69
+ console.log('Loaded connections:', this.connections);
70
+ console.log('Available forms:', this.forms);
71
+
72
+ // Update node ID counter
73
+ if (this.nodes.length > 0) {
74
+ this.store.seedNodeIdCounterFromNodes(this.nodes);
75
+ }
76
+
77
+ this.initializeNodeStackOrder();
78
+ if (this.layoutNeedsNormalization()) {
79
+ this.autoArrangeNodes({ suppressRender: true, silent: true });
80
+ }
81
+ } else {
82
+ console.error('Failed to load workflow:', data.error);
83
+ this.setBuilderMessage('danger', 'Failed to load workflow builder data.', [data.error || 'Unknown error']);
84
+ }
85
+ } catch (error) {
86
+ console.error('Error loading workflow:', error);
87
+ this.setBuilderMessage('danger', 'Failed to load workflow builder data.', [error.message || 'Unknown error']);
88
+ }
89
+ },
90
+
91
+ async saveWorkflow() {
92
+ const validation = this.refreshValidationState();
93
+ if (validation.errors.length) {
94
+ this.setSaveStatus('Fix validation errors', 'danger');
95
+ this.setBuilderMessage(
96
+ 'danger',
97
+ 'Fix validation errors before saving.',
98
+ validation.errors
99
+ );
100
+ if (validation.firstErrorNodeId) {
101
+ this.selectNode(validation.firstErrorNodeId);
102
+ }
103
+ return;
104
+ }
105
+
106
+ const saveBtn = document.getElementById('btnSave');
107
+ const originalText = saveBtn.innerHTML;
108
+ this.isSaving = true;
109
+ saveBtn.disabled = true;
110
+ saveBtn.innerHTML = '<i class="bi bi-hourglass-split"></i> Saving...';
111
+ this.setSaveStatus('Saving...', 'info');
112
+ this.setBuilderMessage(
113
+ validation.warnings.length ? 'warning' : 'info',
114
+ validation.warnings.length
115
+ ? 'Saving workflow with warnings.'
116
+ : 'Saving workflow…',
117
+ validation.warnings
118
+ );
119
+
120
+ const workflowData = {
121
+ form_id: this.config.formId,
122
+ workflow_id: this.config.currentWorkflowId,
123
+ workflow: {
124
+ nodes: this.nodes,
125
+ connections: this.connections
126
+ }
127
+ };
128
+
129
+ console.log('Saving workflow data:', workflowData);
130
+ console.log('Nodes:', this.nodes);
131
+ console.log('Connections:', this.connections);
132
+
133
+ try {
134
+ const response = await fetch(this.config.apiUrls.save, {
135
+ method: 'POST',
136
+ headers: {
137
+ 'Content-Type': 'application/json',
138
+ 'X-CSRFToken': this.config.csrfToken
139
+ },
140
+ body: JSON.stringify(workflowData)
141
+ });
142
+
143
+ console.log('Response status:', response.status);
144
+ console.log('Response ok:', response.ok);
145
+
146
+ const result = await response.json();
147
+ console.log('Response data:', result);
148
+
149
+ if (!response.ok || !result.success) {
150
+ const error = new Error(result.error || 'Failed to save workflow');
151
+ error.details = result.errors || [];
152
+ throw error;
153
+ }
154
+
155
+ if (result.workflow_id) {
156
+ this.config.currentWorkflowId = result.workflow_id;
157
+ }
158
+
159
+ this.syncSavedWorkflowSnapshot();
160
+ this.setSaveStatus('Saved successfully', 'success');
161
+ this.setBuilderMessage(
162
+ 'success',
163
+ 'Workflow saved successfully.',
164
+ validation.warnings.length ? ['Saved with non-blocking warnings shown below.'] : [],
165
+ true
166
+ );
167
+ setTimeout(() => {
168
+ this.setSaveStatus('Ready', 'neutral');
169
+ }, 2000);
170
+ } catch (error) {
171
+ console.error('Error saving workflow:', error);
172
+ this.setBuilderMessage(
173
+ 'danger',
174
+ `Failed to save workflow: ${error.message}`,
175
+ error.details || []
176
+ );
177
+ this.setSaveStatus('Error saving', 'danger');
178
+ } finally {
179
+ this.isSaving = false;
180
+ saveBtn.disabled = false;
181
+ saveBtn.innerHTML = originalText;
182
+ }
183
+ },
184
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Single owner of Workflow Builder state, shared across extracted modules.
3
+ * Factory (not a singleton) since admin inlines can put two builders on one
4
+ * page. Extends EventTarget so modules can react to changes instead of
5
+ * closing over the whole WorkflowBuilder instance. Mirrors
6
+ * form-builder-store.js's BuilderStore/createBuilderStore shape.
7
+ */
8
+ export class WorkflowBuilderStore extends EventTarget {
9
+ constructor({ nodes = [], connections = [], nodeIdCounter = 1 } = {}) {
10
+ super();
11
+ this.nodes = nodes;
12
+ this.connections = connections;
13
+ this.nodeIdCounter = nodeIdCounter;
14
+ }
15
+
16
+ setNodes(nodes) {
17
+ this.nodes = nodes;
18
+ this.dispatchEvent(new CustomEvent('nodes-changed', { detail: { nodes } }));
19
+ }
20
+
21
+ setConnections(connections) {
22
+ this.connections = connections;
23
+ this.dispatchEvent(new CustomEvent('connections-changed', { detail: { connections } }));
24
+ }
25
+
26
+ nextNodeId() {
27
+ const id = `node_${this.nodeIdCounter}`;
28
+ this.nodeIdCounter += 1;
29
+ return id;
30
+ }
31
+
32
+ // Mirrors loadWorkflow()'s existing node-id-counter-seeding logic (and
33
+ // form-builder-store.js's seedFieldIdCounterFromFields) — call after
34
+ // loading nodes from a workflow so newly-generated ids can't collide.
35
+ seedNodeIdCounterFromNodes(nodes) {
36
+ const highest = nodes.reduce((max, node) => {
37
+ const match = /node_(\d+)/.exec(node.id || '');
38
+ return match ? Math.max(max, parseInt(match[1], 10)) : max;
39
+ }, 0);
40
+ this.nodeIdCounter = highest + 1;
41
+ }
42
+
43
+ snapshot() {
44
+ return JSON.stringify({ nodes: this.nodes, connections: this.connections });
45
+ }
46
+
47
+ restore(snapshotJson) {
48
+ const { nodes, connections } = JSON.parse(snapshotJson);
49
+ this.setNodes(nodes);
50
+ this.setConnections(connections);
51
+ }
52
+ }
53
+
54
+ export function createWorkflowBuilderStore(initial) {
55
+ return new WorkflowBuilderStore(initial);
56
+ }