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.
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/CHANGELOG.md +72 -4
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/PKG-INFO +1 -1
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/form_builder_views.py +0 -14
- django_forms_workflows-0.77.0/django_forms_workflows/static/django_forms_workflows/js/workflow-builder-api.js +184 -0
- django_forms_workflows-0.77.0/django_forms_workflows/static/django_forms_workflows/js/workflow-builder-store.js +56 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/tasks.py +75 -11
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/pyproject.toml +1 -1
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/LICENSE +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/README.md +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/admin.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/api_urls.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/api_views.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/apps.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/callback_registry.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/conditions.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/context_processors.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/base.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/database_source.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/ldap_source.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/data_sources/user_source.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/diff_views.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/email_backends/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/email_backends/gmail_api.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/form_builder_urls.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/forms.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/api_handler.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/base.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/database_handler.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/email_handler.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/executor.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/file_handler.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/handlers/ldap_handler.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/history.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/ldap_backend.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/create_default_templates.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/pull_forms.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/push_forms.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/seed_farm_demo.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/seed_pcn_form.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/seed_prefill_sources.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/sync_ldap_profiles.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/sync_ldap_users.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/management/commands/test_db_connection.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0001_initial.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0003_postsubmissionaction.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0004_formtemplate.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0005_advanced_conditional_logic.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0007_add_userprofile_ldap_enhancements.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0008_add_file_workflow_models.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0009_add_formfield_readonly.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0010_add_prefillsource_template_fields.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0012_add_approval_step_fields.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0013_add_database_query_key.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0014_add_form_category.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0015_add_workflowstage_staged_approvals.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0016_add_pdf_generation.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0017_add_notification_batching.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0018_add_form_category_parent.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0019_add_ldap_group_profile.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0020_add_bulk_export_field.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0022_add_bulk_pdf_export.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0023_add_performance_indexes.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0024_add_allow_resubmit.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0025_workflowstage_approve_label.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0026_alter_formfield_width.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0027_formsubmission_form_data_gin.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0028_workflowstagegroupconfig.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0030_formfield_phone_type.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0031_sub_workflows.py +0 -0
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0034_add_notificationlog.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0035_migrate_prefill_source_strings.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0036_add_workflowstage_auto_created.py +0 -0
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0039_update_help_text.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0040_migrate_deprecated_features.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0041_remove_deprecated_fields.py +0 -0
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0044_remove_subworkflowinstance_label.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0045_stageapprovalgroup_workflow_name_label.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0047_add_hide_approval_history.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0049_formfield_multifile_type.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0050_workflowdefinition_collapse_parallel_stages.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0051_formdefinition_is_listed.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0053_stageformfieldnotification_static_emails.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0055_add_send_back.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0056_calculated_formula_spreadsheet.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0057_add_currency_field_type.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0063_formdefinition_api_enabled_apitoken.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0064_add_reviewer_groups.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0065_workflownotification.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0067_migrate_legacy_notify_flags.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0068_drop_legacy_notify_fields.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0069_add_signature_field_type.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0071_alter_pendingnotification_notification_type.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0072_add_change_history.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0074_add_notification_rule.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0075_migrate_to_notification_rules.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0076_update_notification_event_choices.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0077_drop_legacy_notification_models.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0078_allow_anonymous_submissions.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0079_webhookendpoint_webhookdeliverylog.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0081_add_success_page_fields.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0082_add_document_template_model.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0083_workflowdefinition_start_trigger.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0084_add_shared_option_list.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0085_add_payment_system.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0086_add_embed_enabled.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0087_notificationrule_use_triggering_stage.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0089_workflowstage_hide_comment_field.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0091_add_uuid_fields.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0092_add_user_notification_preference.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0093_normalize_conditional_operators.py +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0095_notificationrule_cc_fields.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0096_notificationlog_cc_bcc_emails.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/0097_notificationlog_delivery_reconciliation.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/migrations/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/models.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/base.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/registry.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/stripe_provider.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/payments/views.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/reporting_views.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/signals.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sso_backends.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sso_urls.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sso_views.py +0 -0
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/static/django_forms_workflows/css/forms.css +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sync_api.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/sync_views.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/_category_node.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/_field_value.html +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/analytics_dashboard.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/api/docs.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/approval_inbox.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/approve.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/base.html +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/completed_approvals.html +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/embed_base.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/embed_success.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_categories.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_embed.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_list.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/form_submit.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/my_submissions.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/notification_preferences.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/payment_collect.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/payment_error.html +0 -0
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/rate_limited.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/reassign_task.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/resubmit_confirm.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/sso/login.html +0 -0
- {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
- {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
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_detail.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_pdf.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/submission_success.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/django_forms_workflows/withdraw_confirm.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/approval_notification.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/approval_reminder.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/approval_request.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/email_styles.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/escalation_notification.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/notification_digest.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/rejection_notification.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/emails/submission_notification.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templates/registration/login.html +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templatetags/__init__.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/templatetags/forms_workflows_tags.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/urls.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/utils.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/views.py +0 -0
- {django_forms_workflows-0.76.6 → django_forms_workflows-0.77.0}/django_forms_workflows/workflow_builder_views.py +0 -0
- {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.**
|
|
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
|
-
- **
|
|
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.**
|
|
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.
|
|
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
|
|
@@ -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
|
+
}
|