From fab5de6a98ad50c39104eed32abde391e239885b Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 15:59:11 +0000
Subject: [PATCH 01/35] "Bootstrap 5 Migration - marking export as in progress"
---
.../apps/hqwebapp/utils/bootstrap/status/bootstrap3_to_5.json | 3 +++
1 file changed, 3 insertions(+)
diff --git a/corehq/apps/hqwebapp/utils/bootstrap/status/bootstrap3_to_5.json b/corehq/apps/hqwebapp/utils/bootstrap/status/bootstrap3_to_5.json
index 5ec3f13e4321..3fcf5dcadd51 100644
--- a/corehq/apps/hqwebapp/utils/bootstrap/status/bootstrap3_to_5.json
+++ b/corehq/apps/hqwebapp/utils/bootstrap/status/bootstrap3_to_5.json
@@ -131,5 +131,8 @@
},
"motech.dhis2": {
"is_complete": true
+ },
+ "export": {
+ "in_progress": true
}
}
From 1919bbf00d94a3bcc7b6116b049f53a82964d227 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:10:11 +0000
Subject: [PATCH 02/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/odata_feed_limit_reached_modal.html, splitting templates"
---
.../odata_feed_limit_reached_modal.html | 0
.../odata_feed_limit_reached_modal.html | 29 +++++++++++++++++++
.../partials/export_list_controller.html | 2 +-
3 files changed, 30 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/odata_feed_limit_reached_modal.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/odata_feed_limit_reached_modal.html
diff --git a/corehq/apps/export/templates/export/partials/odata_feed_limit_reached_modal.html b/corehq/apps/export/templates/export/partials/bootstrap3/odata_feed_limit_reached_modal.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/odata_feed_limit_reached_modal.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/odata_feed_limit_reached_modal.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/odata_feed_limit_reached_modal.html b/corehq/apps/export/templates/export/partials/bootstrap5/odata_feed_limit_reached_modal.html
new file mode 100644
index 000000000000..bf29db0c4874
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/odata_feed_limit_reached_modal.html
@@ -0,0 +1,29 @@
+{% load i18n %}
+
+
+
+
+
+
+ {% blocktrans %}
+ At this time we allow a maximum of {{ odata_feed_limit }} OData feeds per project space.
+ Please consider deleting the feeds that you don't need anymore.
+ {% endblocktrans %}
+
+
+
+
+
diff --git a/corehq/apps/export/templates/export/partials/export_list_controller.html b/corehq/apps/export/templates/export/partials/export_list_controller.html
index 3afad8e054f9..6ac3a95b884e 100644
--- a/corehq/apps/export/templates/export/partials/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/export_list_controller.html
@@ -32,7 +32,7 @@
{% if not odata_feeds_over_limit %}
{% include 'export/partials/export_list_create_export_modal.html' %}
{% else %}
- {% include 'export/partials/odata_feed_limit_reached_modal.html' %}
+ {% include 'export/partials/bootstrap3/odata_feed_limit_reached_modal.html' %}
{% endif %}
{% endif %}
From 8dde34ae54762a154a3be88bc1f582d36a5fa4ad Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:10:46 +0000
Subject: [PATCH 03/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/export_list_controller.html, splitting templates"
---
.../export/templates/export/export_list.html | 2 +-
.../export_list_controller.html | 0
.../bootstrap5/export_list_controller.html | 70 +++++++++++++++++++
3 files changed, 71 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/export_list_controller.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
diff --git a/corehq/apps/export/templates/export/export_list.html b/corehq/apps/export/templates/export/export_list.html
index 70e69cbbd3a6..6b4249e3f999 100644
--- a/corehq/apps/export/templates/export/export_list.html
+++ b/corehq/apps/export/templates/export/export_list.html
@@ -40,5 +40,5 @@
{% endif %}
- {% include 'export/partials/export_list_controller.html' with is_daily_saved_export=is_daily_saved_export %}
+ {% include 'export/partials/bootstrap3/export_list_controller.html' with is_daily_saved_export=is_daily_saved_export %}
{% endblock %}
diff --git a/corehq/apps/export/templates/export/partials/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/export_list_controller.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
new file mode 100644
index 000000000000..4bb175a227bd
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
@@ -0,0 +1,70 @@
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+{% load humanize %}
+
+{% if request|toggle_enabled:"PAGINATED_EXPORTS" %}
+
+ {% blocktrans with max_rows=max_normal_export_size|intcomma %}
+ These exports are paginated. That means exports that have over {{ max_rows }} rows will be split into multiple files.
+ {% endblocktrans %}
+
+{% endif %}
+{% if is_deid %}
+
+ {% blocktrans %}
+ These {{ export_type_plural }} are De-Identified , meaning that
+ the administrator of this domain has removed all personally-identifying
+ properties from the exported data.
+ {% endblocktrans %}
+
+{% endif %}
+{% if has_edit_permissions %}
+
+{% endif %}
+
+
+
{# todo B5: inline style #}
+ {% if allow_bulk_export %} {# form exports only #}
+ {% include 'export/partials/export_bulk_notice.html' %}
+ {% endif %}
+ {% if has_edit_permissions %}
+ {% include 'export/partials/delete_bulk_notice.html' %}
+ {% endif %}
+
+
{# todo B5: inline style #}
+
{# todo B5: css:panel #}
+
+
+ {% include 'export/partials/loading_exports.html' %}
+ {% include 'export/partials/table.html' %}
+
+
+
+
+
+ {% if export_filter_form %}
+ {% include 'export/partials/feed_filter_modal.html' %}
+ {% endif %}
+
From 400fd51cf0138b7b88b56d4afd0d0ad9ac599e8d Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:11:21 +0000
Subject: [PATCH 04/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/delete_bulk_notice.html, splitting templates"
---
.../{ => bootstrap3}/delete_bulk_notice.html | 0
.../bootstrap3/export_list_controller.html | 2 +-
.../bootstrap5/delete_bulk_notice.html | 31 +++++++++++++++++++
.../bootstrap5/export_list_controller.html | 2 +-
4 files changed, 33 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/delete_bulk_notice.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html
diff --git a/corehq/apps/export/templates/export/partials/delete_bulk_notice.html b/corehq/apps/export/templates/export/partials/bootstrap3/delete_bulk_notice.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/delete_bulk_notice.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/delete_bulk_notice.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
index 6ac3a95b884e..4930dac07c68 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
@@ -43,7 +43,7 @@
{% include 'export/partials/export_bulk_notice.html' %}
{% endif %}
{% if has_edit_permissions %}
- {% include 'export/partials/delete_bulk_notice.html' %}
+ {% include 'export/partials/bootstrap3/delete_bulk_notice.html' %}
{% endif %}
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html b/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html
new file mode 100644
index 000000000000..c8d2eceddef0
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html
@@ -0,0 +1,31 @@
+{% load i18n %}
+
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
index 4bb175a227bd..099ab30d9865 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
@@ -43,7 +43,7 @@
{% include 'export/partials/export_bulk_notice.html' %}
{% endif %}
{% if has_edit_permissions %}
- {% include 'export/partials/delete_bulk_notice.html' %}
+ {% include 'export/partials/bootstrap5/delete_bulk_notice.html' %}
{% endif %}
{# todo B5: inline style #}
From 5cab4d439ff2555542666dd20187a0647e202d4f Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:11:49 +0000
Subject: [PATCH 05/35] "Bootstrap 5 Migration - initial auto-migration for
export/download_export.html, splitting templates"
---
.../{ => bootstrap3}/download_export.html | 0
.../export/bootstrap5/download_export.html | 107 ++++++++++++++++++
corehq/apps/export/views/download.py | 2 +-
3 files changed, 108 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/{ => bootstrap3}/download_export.html (100%)
create mode 100644 corehq/apps/export/templates/export/bootstrap5/download_export.html
diff --git a/corehq/apps/export/templates/export/download_export.html b/corehq/apps/export/templates/export/bootstrap3/download_export.html
similarity index 100%
rename from corehq/apps/export/templates/export/download_export.html
rename to corehq/apps/export/templates/export/bootstrap3/download_export.html
diff --git a/corehq/apps/export/templates/export/bootstrap5/download_export.html b/corehq/apps/export/templates/export/bootstrap5/download_export.html
new file mode 100644
index 000000000000..0728b458dd4d
--- /dev/null
+++ b/corehq/apps/export/templates/export/bootstrap5/download_export.html
@@ -0,0 +1,107 @@
+{% extends 'hqwebapp/bootstrap5/base_section.html' %}
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+{% load compress %}
+
+{% block stylesheets %}
+
+{% endblock stylesheets %}
+
+{% requirejs_main_b5 'export/js/download_export' %}
+
+{% block page_title %}
+ {{ current_page.title }}
+{% endblock %}
+
+{% block page_content %}
+ {% initial_page_data 'export_list' export_list %}
+ {% initial_page_data 'form_or_case' form_or_case %}
+ {% initial_page_data 'max_column_size' max_column_size %}
+ {% initial_page_data 'default_date_range' default_date_range %}
+ {% initial_page_data 'check_for_multimedia' check_for_multimedia %}
+ {% initial_page_data 'sms_export' sms_export %}
+ {% initial_page_data 'user_types' user_types %}
+
+ {% registerurl 'add_export_email_request' domain %}
+ {% registerurl 'has_multimedia' domain %}
+ {% registerurl 'poll_custom_export_download' domain %}
+ {% registerurl 'prepare_custom_export' domain %}
+ {% registerurl 'prepare_form_multimedia' domain %}
+
+
+ {% include 'export/partials/export_download_progress.html' %}
+
+{% endblock page_content %}
diff --git a/corehq/apps/export/views/download.py b/corehq/apps/export/views/download.py
index 0e2515f263c8..d6491f1b24d5 100644
--- a/corehq/apps/export/views/download.py
+++ b/corehq/apps/export/views/download.py
@@ -149,7 +149,7 @@ def get_export(self, export_id=None):
class BaseDownloadExportView(BaseProjectDataView):
- template_name = 'export/download_export.html'
+ template_name = 'export/bootstrap3/download_export.html'
http_method_names = ['get', 'post']
show_date_range = False
check_for_multimedia = False
From 2b67a92c6d282d9c7251d3ce382732d732ef4406 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:13:37 +0000
Subject: [PATCH 06/35] "Bootstrap 5 Migration - initial auto-migration for
export/customize_export_new.html, splitting templates"
---
.../customize_export_new.html | 0
.../bootstrap5/customize_export_new.html | 356 ++++++++++++++++++
corehq/apps/export/views/new.py | 2 +-
3 files changed, 357 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/{ => bootstrap3}/customize_export_new.html (100%)
create mode 100644 corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
diff --git a/corehq/apps/export/templates/export/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
similarity index 100%
rename from corehq/apps/export/templates/export/customize_export_new.html
rename to corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
diff --git a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
new file mode 100644
index 000000000000..929a3e4f872d
--- /dev/null
+++ b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
@@ -0,0 +1,356 @@
+{% extends "hqwebapp/bootstrap5/base_section.html" %}
+{% load hq_shared_tags %}
+{% load i18n %}
+
+{% requirejs_main_b5 'export/js/customize_export_new' %}
+
+{% block page_content %}
+ {% initial_page_data 'number_of_apps_to_process' number_of_apps_to_process %}
+ {% initial_page_data 'format_options' format_options %}
+ {% initial_page_data 'sharing_options' sharing_options %}
+ {% initial_page_data 'has_other_owner' has_other_owner %}
+ {% initial_page_data 'has_daily_saved_export_access' has_daily_saved_export_access %}
+ {% initial_page_data 'has_excel_dashboard_access' has_excel_dashboard_access %}
+ {% initial_page_data 'full_path' request.get_full_path %}
+ {% initial_page_data 'export_instance' export_instance %}
+ {% initial_page_data 'geo_properties' geo_properties %}
+
+ {# todo B5: inline style #}
+ {# content for multi-select help popover #}
+ {% if export_instance.type == 'case' %}
+
{# todo B5: inline style #}
+ {% blocktrans %}
+ These options allow you to configure how CommCare exports data from multi-select questions.
+ If you do not want to split the options into multiple columns select the 'plain' option.
+ {% endblocktrans %}
+
+ {% blocktrans %}
+ Each item that is selected in the select list will appear as a column in the exported data.
+ Any options not selected will be in an "extra" column.
+ {% endblocktrans %}
+
+ {% trans "More info" %}
+
+
+ {% endif %}
+
+ {% include "export/partials/customize_export_header.html" %}
+
+
+
+ {% include "export/partials/new_customize_export_templates.html" %}
+{% endblock %}
diff --git a/corehq/apps/export/views/new.py b/corehq/apps/export/views/new.py
index e4943cf82d4e..f92c11ac1a5d 100644
--- a/corehq/apps/export/views/new.py
+++ b/corehq/apps/export/views/new.py
@@ -63,7 +63,7 @@
class BaseExportView(BaseProjectDataView):
"""Base class for all create and edit export views"""
- template_name = 'export/customize_export_new.html'
+ template_name = 'export/bootstrap3/customize_export_new.html'
export_type = None
metric_name = None # Override
is_async = True
From e7ba335346b69458b63012df56dd1d3371253cf1 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:14:12 +0000
Subject: [PATCH 07/35] "Bootstrap 5 Migration - initial auto-migration for
export/export_list.html, splitting templates"
---
.../export/{ => bootstrap3}/export_list.html | 0
.../export/bootstrap5/export_list.html | 44 +++++++++++++++++++
corehq/apps/export/views/list.py | 2 +-
3 files changed, 45 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/{ => bootstrap3}/export_list.html (100%)
create mode 100644 corehq/apps/export/templates/export/bootstrap5/export_list.html
diff --git a/corehq/apps/export/templates/export/export_list.html b/corehq/apps/export/templates/export/bootstrap3/export_list.html
similarity index 100%
rename from corehq/apps/export/templates/export/export_list.html
rename to corehq/apps/export/templates/export/bootstrap3/export_list.html
diff --git a/corehq/apps/export/templates/export/bootstrap5/export_list.html b/corehq/apps/export/templates/export/bootstrap5/export_list.html
new file mode 100644
index 000000000000..570eab1b9c7f
--- /dev/null
+++ b/corehq/apps/export/templates/export/bootstrap5/export_list.html
@@ -0,0 +1,44 @@
+{% extends 'hqwebapp/bootstrap3/base_section.html' %}
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+{% load compress %}
+
+{% requirejs_main_b5 'export/js/export_list_main' %}
+
+{% block page_title %}
+ {{ current_page.title }}
+{% endblock %}
+
+{% block page_content %}
+ {% initial_page_data 'bulk_download_url' bulk_download_url %}
+ {% initial_page_data 'exports' exports %}
+ {% initial_page_data 'export_type_caps_plural' export_type_caps_plural %}
+ {% initial_page_data 'is_daily_saved_export' is_daily_saved_export|default:False %}
+ {% initial_page_data 'is_deid' is_deid %}
+ {% initial_page_data 'is_feed' is_feed|default:False %}
+ {% initial_page_data 'is_odata' is_odata|default:False %}
+ {% initial_page_data 'model_type' model_type %}
+ {% initial_page_data 'my_export_type' my_export_type %}
+ {% initial_page_data 'shared_export_type' shared_export_type %}
+ {% initial_page_data 'static_model_type' static_model_type %}
+ {% initial_page_data 'domain' domain %}
+ {% initial_page_data 'export_ownership_enabled' export_ownership_enabled %}
+ {% registerurl 'commit_filters' domain %}
+ {% registerurl 'get_app_data_drilldown_values' domain %}
+ {% registerurl 'get_exports_page' domain %}
+ {% registerurl 'get_saved_export_progress' domain %}
+ {% registerurl 'submit_app_data_drilldown_form' domain %}
+ {% registerurl 'toggle_saved_export_enabled' domain %}
+ {% registerurl 'update_emailed_export_data' domain %}
+
+ {{ lead_text }}
+
+ {% if is_odata %}
+
+
+
+ {% endif %}
+
+ {% include 'export/partials/bootstrap5/export_list_controller.html' with is_daily_saved_export=is_daily_saved_export %}
+{% endblock %}
diff --git a/corehq/apps/export/views/list.py b/corehq/apps/export/views/list.py
index 9de8a6766417..3e81fcc311c8 100644
--- a/corehq/apps/export/views/list.py
+++ b/corehq/apps/export/views/list.py
@@ -496,7 +496,7 @@ def create_export_form(self):
class BaseExportListView(BaseProjectDataView):
- template_name = 'export/export_list.html'
+ template_name = 'export/bootstrap3/export_list.html'
lead_text = mark_safe(gettext_lazy( # nosec: no user input
'''
Exports are a way to download data in a variety of formats (CSV, Excel, etc.)
From 589658070192702c86ef75b5ffc5ce6ae041cc3c Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:14:27 +0000
Subject: [PATCH 08/35] "Bootstrap 5 Migration - initial auto-migration for
export/dialogs/process_deprecated_properties.html, splitting templates"
---
.../bootstrap3/customize_export_new.html | 2 +-
.../bootstrap5/customize_export_new.html | 2 +-
.../process_deprecated_properties.html | 0
.../process_deprecated_properties.html | 33 +++++++++++++++++++
4 files changed, 35 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/dialogs/{ => bootstrap3}/process_deprecated_properties.html (100%)
create mode 100644 corehq/apps/export/templates/export/dialogs/bootstrap5/process_deprecated_properties.html
diff --git a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
index 857425601a48..bf75da725c89 100644
--- a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
@@ -348,7 +348,7 @@
{% include "export/dialogs/process_deleted_questions.html" %}
- {% include "export/dialogs/process_deprecated_properties.html" %}
+ {% include "export/dialogs/bootstrap3/process_deprecated_properties.html" %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
index 929a3e4f872d..995955fd6e94 100644
--- a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
@@ -348,7 +348,7 @@
{% include "export/dialogs/process_deleted_questions.html" %}
- {% include "export/dialogs/process_deprecated_properties.html" %}
+ {% include "export/dialogs/bootstrap5/process_deprecated_properties.html" %}
diff --git a/corehq/apps/export/templates/export/dialogs/process_deprecated_properties.html b/corehq/apps/export/templates/export/dialogs/bootstrap3/process_deprecated_properties.html
similarity index 100%
rename from corehq/apps/export/templates/export/dialogs/process_deprecated_properties.html
rename to corehq/apps/export/templates/export/dialogs/bootstrap3/process_deprecated_properties.html
diff --git a/corehq/apps/export/templates/export/dialogs/bootstrap5/process_deprecated_properties.html b/corehq/apps/export/templates/export/dialogs/bootstrap5/process_deprecated_properties.html
new file mode 100644
index 000000000000..2788b8c249b8
--- /dev/null
+++ b/corehq/apps/export/templates/export/dialogs/bootstrap5/process_deprecated_properties.html
@@ -0,0 +1,33 @@
+{% load hq_shared_tags %}
+{% load i18n %}
+
+
+
+
+
+
+ {% blocktrans %}
+ In order to show you your deprecated properties, we need to refresh the page and
+ load in all the properties. This operation can sometimes take a few minutes.
+ {% endblocktrans %}
+
+
+
+
+
+
+
From 689edbfe4524759a4aa5fde9e4b8743b091127c2 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:15:01 +0000
Subject: [PATCH 09/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/export_download_prepare.html, splitting templates"
---
.../export/bootstrap3/download_export.html | 2 +-
.../export/bootstrap5/download_export.html | 2 +-
.../export_download_prepare.html | 0
.../bootstrap5/export_download_prepare.html | 57 +++++++++++++++++++
4 files changed, 59 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/export_download_prepare.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/export_download_prepare.html
diff --git a/corehq/apps/export/templates/export/bootstrap3/download_export.html b/corehq/apps/export/templates/export/bootstrap3/download_export.html
index a9f968f38e24..e0abb16bfffc 100644
--- a/corehq/apps/export/templates/export/bootstrap3/download_export.html
+++ b/corehq/apps/export/templates/export/bootstrap3/download_export.html
@@ -99,7 +99,7 @@
{% else %}
- {% include 'export/partials/export_download_prepare.html' %}
+ {% include 'export/partials/bootstrap3/export_download_prepare.html' %}
{% endif %}
{% include 'export/partials/export_download_progress.html' %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/download_export.html b/corehq/apps/export/templates/export/bootstrap5/download_export.html
index 0728b458dd4d..5bf0ebce4952 100644
--- a/corehq/apps/export/templates/export/bootstrap5/download_export.html
+++ b/corehq/apps/export/templates/export/bootstrap5/download_export.html
@@ -99,7 +99,7 @@
{% else %}
- {% include 'export/partials/export_download_prepare.html' %}
+ {% include 'export/partials/bootstrap5/export_download_prepare.html' %}
{% endif %}
{% include 'export/partials/export_download_progress.html' %}
diff --git a/corehq/apps/export/templates/export/partials/export_download_prepare.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_download_prepare.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/export_download_prepare.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/export_download_prepare.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_download_prepare.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_download_prepare.html
new file mode 100644
index 000000000000..b4b539ea2472
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_download_prepare.html
@@ -0,0 +1,57 @@
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+
+
+
+
+
From 9344d0376cb0dde193299be0e907251ea58539db Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:17:36 +0000
Subject: [PATCH 10/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/export_download_progress.html, splitting templates"
---
.../export/bootstrap3/download_export.html | 2 +-
.../export/bootstrap5/download_export.html | 2 +-
.../export_download_progress.html | 0
.../bootstrap5/export_download_progress.html | 78 +++++++++++++++++++
4 files changed, 80 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/export_download_progress.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/export_download_progress.html
diff --git a/corehq/apps/export/templates/export/bootstrap3/download_export.html b/corehq/apps/export/templates/export/bootstrap3/download_export.html
index e0abb16bfffc..e8d7bf7641a5 100644
--- a/corehq/apps/export/templates/export/bootstrap3/download_export.html
+++ b/corehq/apps/export/templates/export/bootstrap3/download_export.html
@@ -102,6 +102,6 @@
{% include 'export/partials/bootstrap3/export_download_prepare.html' %}
{% endif %}
- {% include 'export/partials/export_download_progress.html' %}
+ {% include 'export/partials/bootstrap3/export_download_progress.html' %}
{% endblock page_content %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/download_export.html b/corehq/apps/export/templates/export/bootstrap5/download_export.html
index 5bf0ebce4952..4b3d1211ac82 100644
--- a/corehq/apps/export/templates/export/bootstrap5/download_export.html
+++ b/corehq/apps/export/templates/export/bootstrap5/download_export.html
@@ -102,6 +102,6 @@
{% include 'export/partials/bootstrap5/export_download_prepare.html' %}
{% endif %}
- {% include 'export/partials/export_download_progress.html' %}
+ {% include 'export/partials/bootstrap5/export_download_progress.html' %}
{% endblock page_content %}
diff --git a/corehq/apps/export/templates/export/partials/export_download_progress.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_download_progress.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/export_download_progress.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/export_download_progress.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_download_progress.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_download_progress.html
new file mode 100644
index 000000000000..33a55bda96f9
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_download_progress.html
@@ -0,0 +1,78 @@
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+
+
From cec758f5b901ba36181a1d767de9497916f5e67a Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:18:17 +0000
Subject: [PATCH 11/35] "Bootstrap 5 Migration - initial auto-migration for
export/datasource_export_view.html, splitting templates"
---
.../datasource_export_view.html | 0
.../bootstrap5/datasource_export_view.html | 27 +++++++++++++++++++
corehq/apps/export/views/download.py | 2 +-
3 files changed, 28 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/{ => bootstrap3}/datasource_export_view.html (100%)
create mode 100644 corehq/apps/export/templates/export/bootstrap5/datasource_export_view.html
diff --git a/corehq/apps/export/templates/export/datasource_export_view.html b/corehq/apps/export/templates/export/bootstrap3/datasource_export_view.html
similarity index 100%
rename from corehq/apps/export/templates/export/datasource_export_view.html
rename to corehq/apps/export/templates/export/bootstrap3/datasource_export_view.html
diff --git a/corehq/apps/export/templates/export/bootstrap5/datasource_export_view.html b/corehq/apps/export/templates/export/bootstrap5/datasource_export_view.html
new file mode 100644
index 000000000000..297dba911202
--- /dev/null
+++ b/corehq/apps/export/templates/export/bootstrap5/datasource_export_view.html
@@ -0,0 +1,27 @@
+{% extends 'hqwebapp/bootstrap3/base_section.html' %}
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load compress %}
+{% load hq_shared_tags %}
+
+{% requirejs_main_b5 'export/js/datasource_export' %}
+
+{% block page_title %}
+{% trans "Export Data Source Data" %}
+{% endblock %}
+
+{% block page_content %}
+
+ {% blocktrans %}
+ Generate a query file for the Data Export Tool from any of the project's data sources.
+ {% endblocktrans %}
+
+
+{% endblock %}
diff --git a/corehq/apps/export/views/download.py b/corehq/apps/export/views/download.py
index d6491f1b24d5..a221b67177fa 100644
--- a/corehq/apps/export/views/download.py
+++ b/corehq/apps/export/views/download.py
@@ -528,7 +528,7 @@ def parent_pages(self):
class DownloadNewDatasourceExportView(BaseProjectDataView):
urlname = "data_export_page"
page_title = gettext_noop("Export Data Source Data")
- template_name = 'export/datasource_export_view.html'
+ template_name = 'export/bootstrap3/datasource_export_view.html'
def dispatch(self, *args, **kwargs):
if not EXPORT_DATA_SOURCE_DATA.enabled(self.domain):
From 1ddde0784dc1a5d26734b737beb5180d79e2ed09 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:21:34 +0000
Subject: [PATCH 12/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/new_customize_export_templates.html, splitting templates"
---
.../bootstrap3/customize_export_new.html | 2 +-
.../bootstrap5/customize_export_new.html | 2 +-
.../new_customize_export_templates.html | 0
.../new_customize_export_templates.html | 448 ++++++++++++++++++
4 files changed, 450 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/new_customize_export_templates.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/new_customize_export_templates.html
diff --git a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
index bf75da725c89..1fe33dab4c51 100644
--- a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
@@ -352,5 +352,5 @@
- {% include "export/partials/new_customize_export_templates.html" %}
+ {% include "export/partials/bootstrap3/new_customize_export_templates.html" %}
{% endblock %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
index 995955fd6e94..9c3da1af6f24 100644
--- a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
@@ -352,5 +352,5 @@
- {% include "export/partials/new_customize_export_templates.html" %}
+ {% include "export/partials/bootstrap5/new_customize_export_templates.html" %}
{% endblock %}
diff --git a/corehq/apps/export/templates/export/partials/new_customize_export_templates.html b/corehq/apps/export/templates/export/partials/bootstrap3/new_customize_export_templates.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/new_customize_export_templates.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/new_customize_export_templates.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/new_customize_export_templates.html b/corehq/apps/export/templates/export/partials/bootstrap5/new_customize_export_templates.html
new file mode 100644
index 000000000000..e2504697cee8
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/new_customize_export_templates.html
@@ -0,0 +1,448 @@
+{% load hq_shared_tags %}
+{% load i18n %}
+
+
+
From 2c22f4b4049662177d9199be9a70a14ce4785785 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:22:05 +0000
Subject: [PATCH 13/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/export_list_create_export_modal.html, splitting templates"
---
.../bootstrap3/export_list_controller.html | 2 +-
.../export_list_create_export_modal.html | 0
.../bootstrap5/export_list_controller.html | 2 +-
.../export_list_create_export_modal.html | 116 ++++++++++++++++++
4 files changed, 118 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/export_list_create_export_modal.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/export_list_create_export_modal.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
index 4930dac07c68..8dac09ef13b0 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
@@ -30,7 +30,7 @@
{% if not odata_feeds_over_limit %}
- {% include 'export/partials/export_list_create_export_modal.html' %}
+ {% include 'export/partials/bootstrap3/export_list_create_export_modal.html' %}
{% else %}
{% include 'export/partials/bootstrap3/odata_feed_limit_reached_modal.html' %}
{% endif %}
diff --git a/corehq/apps/export/templates/export/partials/export_list_create_export_modal.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_create_export_modal.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/export_list_create_export_modal.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/export_list_create_export_modal.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
index 099ab30d9865..d804dcb4fc90 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
@@ -30,7 +30,7 @@
{% if not odata_feeds_over_limit %}
- {% include 'export/partials/export_list_create_export_modal.html' %}
+ {% include 'export/partials/bootstrap5/export_list_create_export_modal.html' %}
{% else %}
{% include 'export/partials/bootstrap5/odata_feed_limit_reached_modal.html' %}
{% endif %}
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_create_export_modal.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_create_export_modal.html
new file mode 100644
index 000000000000..1f54da3a978f
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_create_export_modal.html
@@ -0,0 +1,116 @@
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+
+
+
+
+
+
+
+ {% trans 'Loading Form' %}
+
+
+
+
+
+
+ {% blocktrans %}If this problem persists, please Report an Issue .{% endblocktrans %}
+
+
+ {% crispy create_export_form %} {# todo B5: check crispy #}
+
+ {% blocktrans %}
+ This application does not appear to be using
+
case management.
+ {% endblocktrans %}
+
+
+
+
+
+
+ {% trans "Mislabeled" %}
+
+
{# todo B5: css:well #}
+
{% trans "Suggestions" %}
+
+ {% trans "These form submissions are tagged as if they belong to an application that doesn't exist." %}
+
+
+
{% trans "These submissions could belong to one of the following forms:" %}
+
+
+ >
+
+
+ {% trans "App was deleted." %}
+
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ Preparing {{ export_type_caps }} Data...
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ Please note that this may take several minutes.
+ Thank you for your patience!
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ If this problem persists, please Report an Issue and include this error
+ message in the description.
+ {% endblocktrans %}
+
+
+
+
+ {% blocktrans %}
+ It seems as though you haven't submitted any data to CommCare HQ.
+ Please deploy an application and submit data before creating any {{ export_type_plural }}.
+ {% endblocktrans %}
+
+
+
+ {% trans 'How to Create and Deploy a CommCare Application.' %}
+
+
+
+
+
+
+
From 41faae9af0c45e8428ab792c095e451ac168c2ee Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:25:09 +0000
Subject: [PATCH 14/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/table.html, splitting templates"
---
.../bootstrap3/export_list_controller.html | 2 +-
.../partials/{ => bootstrap3}/table.html | 0
.../bootstrap5/export_list_controller.html | 2 +-
.../export/partials/bootstrap5/table.html | 713 ++++++++++++++++++
4 files changed, 715 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/table.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/table.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
index 8dac09ef13b0..da09c9d35691 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
@@ -51,7 +51,7 @@
{% include 'export/partials/loading_exports.html' %}
- {% include 'export/partials/table.html' %}
+ {% include 'export/partials/bootstrap3/table.html' %}
{% include 'export/partials/loading_exports.html' %}
- {% include 'export/partials/table.html' %}
+ {% include 'export/partials/bootstrap5/table.html' %}
+
+
+ {% if has_edit_permissions or allow_bulk_export %}
+
+ {% blocktrans %}Select{% endblocktrans %}
+
+
+ {% trans 'All' %}
+
+ {%trans 'or'%}
+
+ {% trans 'None' %}
+
+
+ {% endif %}
+
+ {% trans 'Name' %}
+
+
+ {% if model_type == "case" %}
+
+ {% trans 'Case Type' %}
+
+ {% endif %}
+
+
+ {% if export_filter_form %}
+ {% if has_edit_permissions %}
+ {% trans "Filters and Files" %}
+ {% endif %}
+ {% else %}
+ {{ export_type_caps }}
+ {% endif %}
+
+
+ {% if is_daily_saved_export %}
+ {% trans "Enable/Disable" %}
+ {% endif %}
+
+ {% if has_edit_permissions %}
+
+ {% if is_daily_saved_export %}
+ {% trans "Edit Columns" %}
+ {% elif not is_odata %}
+ {% trans 'Edit' %}
+ {% else %}
+ {% blocktrans %}
+ Copy & Edit Feed
+ {% endblocktrans %}
+ {% endif %}
+
+
+ {% trans 'Delete' %}
+
+ {% endif %}
+
+ {% if request|request_has_privilege:"EXPORT_OWNERSHIP" %}
+
+
+ {% trans "Share" %}
+
+
+ {% trans "Shared By" %}
+
+
+ {% endif %}
+
+
+
+
+ {% if has_edit_permissions or allow_bulk_export %}
+
+ {# todo B5: css:checkbox #}
+
+
+
+
+
+ {% endif %}
+
+
+
+
+ {% trans 'De-Identified' %}
+
+
+
+
+
+ {% trans 'Form:' %}
+
+
+
+
+
+
+
+ {% blocktrans %}
+ This export is filtered to data you don't have access to.
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans "Show additional feeds for Repeat Group data." %}
+
+
+ {% trans "Show additional feeds for linking Parent and Child Cases." %}
+
+
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ Click to copy feeds for Repeat Group data:
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ Click to copy feeds for linking Parent
+ and Child Cases :
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ Automatic updates for this saved {{ export_type }} have been disabled. Click 'Enable'
+ to re-enable automatic updates.
+ {% endblocktrans %}
+
+
+
+
+
+
+
+ {% trans "Size:" %}
+
+
+
+ {% trans "Last Updated:" %}
+
+
+
+
+
+ {% trans "Just now" %}
+
+
+ {% trans "Last Downloaded:" %}
+
+
+ {% if request|toggle_enabled:"SUPPORT" %}
+
+
+ {% trans "Last Build Duration:" %}
+
+
+
+ {% endif %}
+
+
+
+
+
+ {% trans "Update Data" %}
+
+
+
+ {% trans "Updating Data, please wait..." %}
+
+
+
{# todo B5: css:progress #}
+
+
+
+
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ This saved {{ export_type }} has expired because it has not been used in
+ the last 35 days. To renew daily updates, click the 'Update Data'
+ button and download the file.
+ {% endblocktrans %}
+
+
+
+
+ {% blocktrans with max_rows=max_daily_export_size|intcomma %}
+ Your export exceeds the limit of {{ max_rows }} rows. Please see documentation for more information.
+ {% endblocktrans %}
+
+
+
+
+
+ {% trans "Data update complete" %}
+
+
+
+
+
+
+ {% trans "Data update failed!" %}
+
+ {% blocktrans %}
+ If this problem persists, please Report an Issue .
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ No data is available yet.
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ Please click 'update data' if the automatic scheduler hasn't picked up the changes in a while.
+ {% endblocktrans %}
+
+
+
+
+
+
+
+ {% blocktrans %}
+ To renew daily updates, click the Update Data button below and check back in a little
+ bit once the updates have finished processing.
+ {% endblocktrans %}
+
+
+
+
+ {% blocktrans %}
+ Once the data is updated, a data refresh should
+ occur automatically on a daily basis.
+ {% endblocktrans %}
+
+
+
+ {% blocktrans %}
+ To download data now, please click the Export button instead.
+ {% endblocktrans %}
+
+
+ To export data now, please copy the dashboard feed link instead.
+
+
+ To export data now, please click the Download button instead.
+
+
+
+
+
+
+
+
+
+
+
+
+ {% blocktrans %}
+ This will enable the daily automatic updates of this export.
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ This will disable the daily automatic updates of this export.
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
+
+
+ {% if model_type == "case" %}
+
+ {# todo B5: inline style #}
+ {% trans "deprecated" %} {# todo B5: inline style #}
+
+ {% endif %}
+
+
+
+ {{ export_type_caps }}
+
+ {% if has_edit_permissions %}
+
+
+ {% trans "Edit Filters" %}
+
+ {% endif %}
+ {% trans "Download a Data Export Tool configuration file for this export" as det_help %}
+
+
+ {% trans "DET Config" %}
+
+
+
+ {% if is_daily_saved_export %}
+
+
+
+
+ {% trans "Enable" %}
+
+
+ {% trans "Disable" %}
+
+
+
+
+ {% endif %}
+
+ {% if has_edit_permissions %}
+
+
+
+
+
+
+
+ {% endif %}
+
+ {% if request|request_has_privilege:"EXPORT_OWNERSHIP" %}
+
+
+
+ {% trans 'Private' %}
+
+
+ {% trans 'Export Only' %}
+
+
+ {% trans 'Edit & Export' %}
+
+
+
+
+
+ {% trans 'Unknown' %}
+
+
+
+
+
+ {% endif %}
+
+
+
+
From 5bfc72d10c0736b2057d7c9d5a957f7e0d6e7c33 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:25:40 +0000
Subject: [PATCH 15/35] "Bootstrap 5 Migration - initial auto-migration for
export/dialogs/bulk_delete_custom_export_dialog.html, splitting templates"
---
.../bulk_delete_custom_export_dialog.html | 0
.../bulk_delete_custom_export_dialog.html | 91 +++++++++++++++++++
.../bootstrap3/delete_bulk_notice.html | 2 +-
.../bootstrap5/delete_bulk_notice.html | 2 +-
4 files changed, 93 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/dialogs/{ => bootstrap3}/bulk_delete_custom_export_dialog.html (100%)
create mode 100644 corehq/apps/export/templates/export/dialogs/bootstrap5/bulk_delete_custom_export_dialog.html
diff --git a/corehq/apps/export/templates/export/dialogs/bulk_delete_custom_export_dialog.html b/corehq/apps/export/templates/export/dialogs/bootstrap3/bulk_delete_custom_export_dialog.html
similarity index 100%
rename from corehq/apps/export/templates/export/dialogs/bulk_delete_custom_export_dialog.html
rename to corehq/apps/export/templates/export/dialogs/bootstrap3/bulk_delete_custom_export_dialog.html
diff --git a/corehq/apps/export/templates/export/dialogs/bootstrap5/bulk_delete_custom_export_dialog.html b/corehq/apps/export/templates/export/dialogs/bootstrap5/bulk_delete_custom_export_dialog.html
new file mode 100644
index 000000000000..3f6fc06b352f
--- /dev/null
+++ b/corehq/apps/export/templates/export/dialogs/bootstrap5/bulk_delete_custom_export_dialog.html
@@ -0,0 +1,91 @@
+{% load hq_shared_tags %}
+{% load i18n %}
+
+
+
+
+
{# todo B5: inline style #}
+
+
+
+ {% blocktrans %}
+ Are you sure you want to permanently delete these feeds ?
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ Are you sure you want to permanently delete this 1 feed ?
+ {% endblocktrans %}
+
+
+
+
+ {% blocktrans %}
+ Are you sure you want to permanently delete these exports ?
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ Are you sure you want to permanently delete this 1 export ?
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
+
+
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/delete_bulk_notice.html b/corehq/apps/export/templates/export/partials/bootstrap3/delete_bulk_notice.html
index 098c0179a2e0..705bdbf71e91 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/delete_bulk_notice.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/delete_bulk_notice.html
@@ -25,7 +25,7 @@
- {% include "export/dialogs/bulk_delete_custom_export_dialog.html" %}
+ {% include "export/dialogs/bootstrap3/bulk_delete_custom_export_dialog.html" %}
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html b/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html
index c8d2eceddef0..6674fc6cf3f5 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/delete_bulk_notice.html
@@ -25,7 +25,7 @@
- {% include "export/dialogs/bulk_delete_custom_export_dialog.html" %}
+ {% include "export/dialogs/bootstrap5/bulk_delete_custom_export_dialog.html" %}
From 7ca3d07b6eff99a33df7946d2027a27d710b7d50 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:25:53 +0000
Subject: [PATCH 16/35] "Bootstrap 5 Migration - initial auto-migration for
export/dialogs/delete_custom_export_dialog.html, splitting templates"
---
.../delete_custom_export_dialog.html | 0
.../delete_custom_export_dialog.html | 48 +++++++++++++++++++
.../export/partials/bootstrap3/table.html | 2 +-
.../export/partials/bootstrap5/table.html | 2 +-
4 files changed, 50 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/dialogs/{ => bootstrap3}/delete_custom_export_dialog.html (100%)
create mode 100644 corehq/apps/export/templates/export/dialogs/bootstrap5/delete_custom_export_dialog.html
diff --git a/corehq/apps/export/templates/export/dialogs/delete_custom_export_dialog.html b/corehq/apps/export/templates/export/dialogs/bootstrap3/delete_custom_export_dialog.html
similarity index 100%
rename from corehq/apps/export/templates/export/dialogs/delete_custom_export_dialog.html
rename to corehq/apps/export/templates/export/dialogs/bootstrap3/delete_custom_export_dialog.html
diff --git a/corehq/apps/export/templates/export/dialogs/bootstrap5/delete_custom_export_dialog.html b/corehq/apps/export/templates/export/dialogs/bootstrap5/delete_custom_export_dialog.html
new file mode 100644
index 000000000000..8ea017321807
--- /dev/null
+++ b/corehq/apps/export/templates/export/dialogs/bootstrap5/delete_custom_export_dialog.html
@@ -0,0 +1,48 @@
+{% load hq_shared_tags %}
+{% load i18n %}
+
+
+
+
+
+ {% csrf_token %}
+
+
+
+ {% blocktrans %}
+ Are you sure you want to delete this feed?
+ {% endblocktrans %}
+
+
+ {% blocktrans %}
+ Are you sure you want to delete this export?
+ {% endblocktrans %}
+
+
+
+
+
+
+
+
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/table.html b/corehq/apps/export/templates/export/partials/bootstrap3/table.html
index de75713471f3..fa8b943838e7 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/table.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/table.html
@@ -678,7 +678,7 @@
{% trans 'Delete' %}
- {% include "export/dialogs/delete_custom_export_dialog.html" %}
+ {% include "export/dialogs/bootstrap3/delete_custom_export_dialog.html" %}
{% endif %}
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/table.html b/corehq/apps/export/templates/export/partials/bootstrap5/table.html
index b0afda2b69e4..a6d89ac09155 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap5/table.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/table.html
@@ -678,7 +678,7 @@ {# todo B5
{% trans 'Delete' %}
- {% include "export/dialogs/delete_custom_export_dialog.html" %}
+ {% include "export/dialogs/bootstrap5/delete_custom_export_dialog.html" %}
{% endif %}
From 34736a3af6eea611e5e09511a9d786af965f0d56 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:26:15 +0000
Subject: [PATCH 17/35] "Bootstrap 5 Migration - initial auto-migration for
export/dialogs/process_deleted_questions.html, splitting templates"
---
.../bootstrap3/customize_export_new.html | 2 +-
.../bootstrap5/customize_export_new.html | 2 +-
.../process_deleted_questions.html | 0
.../bootstrap5/process_deleted_questions.html | 56 +++++++++++++++++++
4 files changed, 58 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/dialogs/{ => bootstrap3}/process_deleted_questions.html (100%)
create mode 100644 corehq/apps/export/templates/export/dialogs/bootstrap5/process_deleted_questions.html
diff --git a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
index 1fe33dab4c51..44d3ea6dbfb9 100644
--- a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
@@ -347,7 +347,7 @@
{% trans "There are errors with your configuration. Please fix them before creating the export." %}
- {% include "export/dialogs/process_deleted_questions.html" %}
+ {% include "export/dialogs/bootstrap3/process_deleted_questions.html" %}
{% include "export/dialogs/bootstrap3/process_deprecated_properties.html" %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
index 9c3da1af6f24..56a635d19428 100644
--- a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
@@ -347,7 +347,7 @@
{% trans "There are errors with your configuration. Please fix them before creating the export." %}
- {% include "export/dialogs/process_deleted_questions.html" %}
+ {% include "export/dialogs/bootstrap5/process_deleted_questions.html" %}
{% include "export/dialogs/bootstrap5/process_deprecated_properties.html" %}
diff --git a/corehq/apps/export/templates/export/dialogs/process_deleted_questions.html b/corehq/apps/export/templates/export/dialogs/bootstrap3/process_deleted_questions.html
similarity index 100%
rename from corehq/apps/export/templates/export/dialogs/process_deleted_questions.html
rename to corehq/apps/export/templates/export/dialogs/bootstrap3/process_deleted_questions.html
diff --git a/corehq/apps/export/templates/export/dialogs/bootstrap5/process_deleted_questions.html b/corehq/apps/export/templates/export/dialogs/bootstrap5/process_deleted_questions.html
new file mode 100644
index 000000000000..3ec569aca543
--- /dev/null
+++ b/corehq/apps/export/templates/export/dialogs/bootstrap5/process_deleted_questions.html
@@ -0,0 +1,56 @@
+{% load hq_shared_tags %}
+{% load i18n %}
+
+
+
+
+
+
+ {% if export_instance.type == 'form' %}
+ {% blocktrans %}
+ In order to show you your deleted questions, we need to process all of your old applications that have
+ had submissions. This operation can sometimes take a few minutes.
+ {% endblocktrans %}
+ {% else %}
+ {% blocktrans %}
+ In order to show you your deleted properties, we need to process all of your old applications that have
+ had submissions. This operation can sometimes take a few minutes.
+ {% endblocktrans %}
+ {% endif %}
+
+
+
+ {% trans "Unable to process applications. Please report an issue if this persists" %}
+
+
+
{# todo B5: css:progress #}
+
+
+
+
+
+
+
From 2caf5bdfad649c8584b6515c96b1886d64c909fe Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:27:46 +0000
Subject: [PATCH 18/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/feed_filter_modal.html, splitting templates"
---
.../bootstrap3/export_list_controller.html | 2 +-
.../{ => bootstrap3}/feed_filter_modal.html | 0
.../bootstrap5/export_list_controller.html | 2 +-
.../bootstrap5/feed_filter_modal.html | 49 +++++++++++++++++++
4 files changed, 51 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/feed_filter_modal.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/feed_filter_modal.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
index da09c9d35691..aff4b7e743e0 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
@@ -65,6 +65,6 @@
{% if export_filter_form %}
- {% include 'export/partials/feed_filter_modal.html' %}
+ {% include 'export/partials/bootstrap3/feed_filter_modal.html' %}
{% endif %}
diff --git a/corehq/apps/export/templates/export/partials/feed_filter_modal.html b/corehq/apps/export/templates/export/partials/bootstrap3/feed_filter_modal.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/feed_filter_modal.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/feed_filter_modal.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
index e2105e9541a8..48a52caf5608 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
@@ -65,6 +65,6 @@
{% if export_filter_form %}
- {% include 'export/partials/feed_filter_modal.html' %}
+ {% include 'export/partials/bootstrap5/feed_filter_modal.html' %}
{% endif %}
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/feed_filter_modal.html b/corehq/apps/export/templates/export/partials/bootstrap5/feed_filter_modal.html
new file mode 100644
index 000000000000..64bd99d79ec1
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/feed_filter_modal.html
@@ -0,0 +1,49 @@
+{% load crispy_forms_tags %}
+{% load i18n %}
+{% load hq_shared_tags %}
+
+
+
+
+
+
+
+
+
+
+
+ {% trans "Location-Limited Data" %}
+
+ {% trans "This export is limited to the following locations:" %}
+
+
+
+ {% crispy export_filter_form %} {# todo B5: check crispy #}
+
+
+ {% trans "There was an unknown error saving the filters" %}
+
+
+
+
+
+
+
+
From 2673272202a2468120e83d1e6b55c4a12876b773 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:28:49 +0000
Subject: [PATCH 19/35] "Bootstrap 5 Migration - initial auto-migration for
export/download_data_files.html, splitting templates"
---
.../{ => bootstrap3}/download_data_files.html | 0
.../bootstrap5/download_data_files.html | 123 ++++++++++++++++++
corehq/apps/export/views/utils.py | 2 +-
3 files changed, 124 insertions(+), 1 deletion(-)
rename corehq/apps/export/templates/export/{ => bootstrap3}/download_data_files.html (100%)
create mode 100644 corehq/apps/export/templates/export/bootstrap5/download_data_files.html
diff --git a/corehq/apps/export/templates/export/download_data_files.html b/corehq/apps/export/templates/export/bootstrap3/download_data_files.html
similarity index 100%
rename from corehq/apps/export/templates/export/download_data_files.html
rename to corehq/apps/export/templates/export/bootstrap3/download_data_files.html
diff --git a/corehq/apps/export/templates/export/bootstrap5/download_data_files.html b/corehq/apps/export/templates/export/bootstrap5/download_data_files.html
new file mode 100644
index 000000000000..485427672a07
--- /dev/null
+++ b/corehq/apps/export/templates/export/bootstrap5/download_data_files.html
@@ -0,0 +1,123 @@
+{% extends "hqwebapp/bootstrap5/base_section.html" %}
+{% load hq_shared_tags %}
+{% load i18n %}
+{% load compress %}
+
+{% block title %}{% trans "Download Files" %}{% endblock %}
+
+
+{% requirejs_main_b5 'export/js/download_data_files' %}
+
+
+{% block page_content %}
+ {% registerurl 'download_data_file' domain '---' '---' %}
+ {% block main_column_content %}
+
+ {% trans "Download Files" %}
+
+ {% if data_files %}
+
+
+
+ {% for data_file in data_files %}
+
+
+
+
+ {{ data_file.filename }}
+
+
+
+ {{ data_file.description }}
+ {{ url_base }}{% url 'download_data_file' domain data_file.id data_file.filename %} {# todo B5: inline style #}
+
+
+ {% trans "Available until" %}: {{ data_file.delete_after|to_user_time:request }}
+
+ {# todo B5: inline style #}
+
+
+
+
+
+
+
+
+ {% if is_admin %}
+
+
+
+ {% endif %}
+
+
+ {% endfor %}
+
+
+
+ {% else %}
+ {% trans "There are no data files available to download at the moment." %}
+ {% endif %}
+
+ {% if is_admin %}
+
+
+ {% endif %}
+
+ {% endblock main_column_content %}
+{% endblock %}
diff --git a/corehq/apps/export/views/utils.py b/corehq/apps/export/views/utils.py
index 3ba95e4f56c2..89bfb95ec669 100644
--- a/corehq/apps/export/views/utils.py
+++ b/corehq/apps/export/views/utils.py
@@ -312,7 +312,7 @@ class DashboardFeedPaywall(BaseProjectDataView):
@method_decorator(login_and_domain_required, name='dispatch')
class DataFileDownloadList(BaseProjectDataView):
urlname = 'download_data_files'
- template_name = 'export/download_data_files.html'
+ template_name = 'export/bootstrap3/download_data_files.html'
page_title = gettext_lazy("Secure File Transfer")
def dispatch(self, request, *args, **kwargs):
From e64892a32f15a13e50967f565d1b68b400767df2 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:30:56 +0000
Subject: [PATCH 20/35] "Bootstrap 5 Migration - initial auto-migration for
export/partials/export_bulk_notice.html, splitting templates"
---
.../{ => bootstrap3}/export_bulk_notice.html | 0
.../bootstrap3/export_list_controller.html | 2 +-
.../bootstrap5/export_bulk_notice.html | 24 +++++++++++++++++++
.../bootstrap5/export_list_controller.html | 2 +-
4 files changed, 26 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/partials/{ => bootstrap3}/export_bulk_notice.html (100%)
create mode 100644 corehq/apps/export/templates/export/partials/bootstrap5/export_bulk_notice.html
diff --git a/corehq/apps/export/templates/export/partials/export_bulk_notice.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_bulk_notice.html
similarity index 100%
rename from corehq/apps/export/templates/export/partials/export_bulk_notice.html
rename to corehq/apps/export/templates/export/partials/bootstrap3/export_bulk_notice.html
diff --git a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
index aff4b7e743e0..9a3f85ca71b4 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap3/export_list_controller.html
@@ -40,7 +40,7 @@
{% if allow_bulk_export %} {# form exports only #}
- {% include 'export/partials/export_bulk_notice.html' %}
+ {% include 'export/partials/bootstrap3/export_bulk_notice.html' %}
{% endif %}
{% if has_edit_permissions %}
{% include 'export/partials/bootstrap3/delete_bulk_notice.html' %}
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_bulk_notice.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_bulk_notice.html
new file mode 100644
index 000000000000..f61a90c0bbbc
--- /dev/null
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_bulk_notice.html
@@ -0,0 +1,24 @@
+{% load i18n %}
+
{# todo B5: inline style #}
+
+ {% csrf_token %}
+ {# todo B5: inline style #}
+
+ {# todo B5: inline style #}
+ {% trans 'Bulk Export' %}
+ ()
+
+
+
+
+
+
diff --git a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
index 48a52caf5608..f35a4f2ae71f 100644
--- a/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
+++ b/corehq/apps/export/templates/export/partials/bootstrap5/export_list_controller.html
@@ -40,7 +40,7 @@
{# todo B5: inline style #}
{% if allow_bulk_export %} {# form exports only #}
- {% include 'export/partials/export_bulk_notice.html' %}
+ {% include 'export/partials/bootstrap5/export_bulk_notice.html' %}
{% endif %}
{% if has_edit_permissions %}
{% include 'export/partials/bootstrap5/delete_bulk_notice.html' %}
From dcc689e1090126c55a5fcaf013fc4f59f15a9b3c Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:31:11 +0000
Subject: [PATCH 21/35] "Bootstrap 5 Migration - initial auto-migration for
export/paywall.html, splitting templates"
---
.../export/{ => bootstrap3}/paywall.html | 0
.../templates/export/bootstrap5/paywall.html | 37 +++++++++++++++++++
corehq/apps/export/views/utils.py | 4 +-
3 files changed, 39 insertions(+), 2 deletions(-)
rename corehq/apps/export/templates/export/{ => bootstrap3}/paywall.html (100%)
create mode 100644 corehq/apps/export/templates/export/bootstrap5/paywall.html
diff --git a/corehq/apps/export/templates/export/paywall.html b/corehq/apps/export/templates/export/bootstrap3/paywall.html
similarity index 100%
rename from corehq/apps/export/templates/export/paywall.html
rename to corehq/apps/export/templates/export/bootstrap3/paywall.html
diff --git a/corehq/apps/export/templates/export/bootstrap5/paywall.html b/corehq/apps/export/templates/export/bootstrap5/paywall.html
new file mode 100644
index 000000000000..85d1f11f7850
--- /dev/null
+++ b/corehq/apps/export/templates/export/bootstrap5/paywall.html
@@ -0,0 +1,37 @@
+{% extends "hqwebapp/bootstrap5/base_section.html" %}
+{% load hq_shared_tags %}
+{% load i18n %}
+{% load compress %}
+
+{% block title %}{% trans "Share Daily Data with Excel and Other Systems" %}{% endblock %}
+
+{% block page_content %}
+ {% block main_column_content %}
+
+
+
+
+ {% blocktrans %}
+ Share Daily Data with Excel and Other Systems
+ {% endblocktrans%}
+
+
+ {% blocktrans %}
+ CommCare can automatically generate an Excel Dashboard Feed or a saved export, allowing you to easily
+ analyze and build reports for your project in Excel or another system. These feeds and exports are
+ updated on a daily-basis with new data and can be filtered to data from a specific set of users or
+ locations. Excel Dashboard Feeds and Daily Saved Exports are available on the Standard or
+ higher software plans.
+ {% endblocktrans %}
+
+
+ {% trans "Learn More About Pricing Plans" %}
+
+
+ {% trans "Change My Subscription" %}
+
+
+
+
+ {% endblock main_column_content %}
+{% endblock %}
diff --git a/corehq/apps/export/views/utils.py b/corehq/apps/export/views/utils.py
index 89bfb95ec669..9c39a0026513 100644
--- a/corehq/apps/export/views/utils.py
+++ b/corehq/apps/export/views/utils.py
@@ -300,12 +300,12 @@ def post(self, request, *args, **kwargs):
class DailySavedExportPaywall(BaseProjectDataView):
urlname = 'daily_saved_paywall'
- template_name = 'export/paywall.html'
+ template_name = 'export/bootstrap3/paywall.html'
class DashboardFeedPaywall(BaseProjectDataView):
urlname = 'dashboard_feeds_paywall'
- template_name = 'export/paywall.html'
+ template_name = 'export/bootstrap3/paywall.html'
@location_safe
From 7a49a5a6d689bbb132a8fb7d79f444795b6f0a67 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:32:20 +0000
Subject: [PATCH 22/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/export_list_main.js, splitting templates"
---
.../js/{ => bootstrap3}/export_list_main.js | 2 +-
.../export/js/bootstrap5/export_list_main.js | 113 ++++++++++++++++++
.../export/bootstrap3/export_list.html | 2 +-
.../export/bootstrap5/export_list.html | 2 +-
4 files changed, 116 insertions(+), 3 deletions(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/export_list_main.js (98%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/export_list_main.js
diff --git a/corehq/apps/export/static/export/js/export_list_main.js b/corehq/apps/export/static/export/js/bootstrap3/export_list_main.js
similarity index 98%
rename from corehq/apps/export/static/export/js/export_list_main.js
rename to corehq/apps/export/static/export/js/bootstrap3/export_list_main.js
index fc0a07f5c3d4..143ad6769f71 100644
--- a/corehq/apps/export/static/export/js/export_list_main.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/export_list_main.js
@@ -1,4 +1,4 @@
-hqDefine("export/js/export_list_main", [
+hqDefine("export/js/bootstrap3/export_list_main", [
'jquery',
'hqwebapp/js/initial_page_data',
'analytix/js/kissmetrix',
diff --git a/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js b/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js
new file mode 100644
index 000000000000..99a0957eae32
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js
@@ -0,0 +1,113 @@
+hqDefine("export/js/bootstrap5/export_list_main", [
+ 'jquery',
+ 'hqwebapp/js/initial_page_data',
+ 'analytix/js/kissmetrix',
+ 'hqwebapp/js/bootstrap5/main',
+ 'export/js/create_export',
+ 'export/js/export_list',
+ 'hqwebapp/js/select_2_ajax_widget', // for case owner & user filters in DashboardFeedFilterForm
+], function (
+ $,
+ initialPageData,
+ kissmetricsAnalytics,
+ utils,
+ createModels,
+ listModels
+) {
+ $(function () {
+ var $createExport = $("#create-export"),
+ isOData = initialPageData.get('is_odata', true);
+
+ if ($createExport.length) {
+ $createExport.koApplyBindings(createModels.createExportModel({
+ model_type: initialPageData.get("model_type", true),
+ drilldown_fetch_url: initialPageData.reverse('get_app_data_drilldown_values'),
+ drilldown_submit_url: initialPageData.reverse('submit_app_data_drilldown_form'),
+ page: {
+ is_daily_saved_export: initialPageData.get('is_daily_saved_export', true),
+ is_feed: initialPageData.get('is_feed', true),
+ is_deid: initialPageData.get('is_deid', true),
+ is_odata: isOData,
+ model_type: initialPageData.get('model_type', true),
+ },
+ }));
+ $('#createExportOptionsModal').on('show.bs.modal', function () {
+ kissmetricsAnalytics.track.event("Clicked New Export");
+
+ if (isOData) {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked + Add Odata Feed button");
+ }
+
+ const exportAction = getExportAction();
+ const metricsMessage = `${exportAction} Export - Clicked Add Export Button`;
+ kissmetricsAnalytics.track.event(metricsMessage, {
+ domain: initialPageData.get('domain'),
+ });
+ });
+ }
+
+ if (isOData) {
+ kissmetricsAnalytics.track.event("[BI Integration] Visited feature page");
+ kissmetricsAnalytics.track.outboundLink(
+ '#js-odata-track-learn-more',
+ "[BI Integration] Clicked Learn More-Wiki"
+ );
+ kissmetricsAnalytics.track.outboundLink(
+ '#js-odata-track-learn-more-preview',
+ "[BI Integration] Clicked Learn More-Feature Preview"
+ );
+ }
+
+ var modelType = initialPageData.get("model_type");
+ $("#export-list").koApplyBindings(listModels.exportListModel({
+ modelType: modelType,
+ isDeid: initialPageData.get('is_deid'),
+ isDailySavedExport: initialPageData.get('is_daily_saved_export', true),
+ isFeed: initialPageData.get('is_feed', true),
+ isOData: isOData,
+ headers: {
+ my_export_type: initialPageData.get('my_export_type'),
+ shared_export_type: initialPageData.get('shared_export_type'),
+ export_type_caps_plural: initialPageData.get('export_type_caps_plural'),
+ },
+ urls: {
+ commitFilters: initialPageData.reverse("commit_filters"),
+ getExportsPage: initialPageData.reverse("get_exports_page"),
+ poll: initialPageData.reverse("get_saved_export_progress"),
+ toggleEnabled: initialPageData.reverse("toggle_saved_export_enabled"),
+ update: initialPageData.reverse("update_emailed_export_data"),
+ },
+ exportOwnershipEnabled: initialPageData.get("export_ownership_enabled"),
+ }));
+
+ if (modelType === 'form') {
+ kissmetricsAnalytics.track.event('Visited Export Forms Page');
+ } else if (modelType === 'case') {
+ kissmetricsAnalytics.track.event('Visited Export Cases Page');
+ }
+
+ // Analytics: Send Kissmetrics event when user closes alert bubble
+ $('#alert-export-deep-links').on('click', function () {
+ kissmetricsAnalytics.track.event("Dismissed alert bubble - Deep links in exports");
+ });
+ });
+
+ function getExportAction() {
+ const modelType = initialPageData.get('model_type', true);
+ if (modelType) {
+ return utils.capitalize(modelType);
+ }
+
+ const isDailySavedExport = initialPageData.get('is_daily_saved_export', true);
+ const isExcelExport = initialPageData.get('is_feed', true);
+ const isOData = initialPageData.get('is_odata', true);
+
+ if (isDailySavedExport) {
+ // NOTE: Currently, excel exports are considered daily exports,
+ // but if this was not intentional, this code should be separated
+ return (isExcelExport ? 'Excel Dashboard' : 'Daily Saved');
+ } else if (isOData) {
+ return 'PowerBI';
+ }
+ }
+});
diff --git a/corehq/apps/export/templates/export/bootstrap3/export_list.html b/corehq/apps/export/templates/export/bootstrap3/export_list.html
index 6b4249e3f999..2bc421fc6a46 100644
--- a/corehq/apps/export/templates/export/bootstrap3/export_list.html
+++ b/corehq/apps/export/templates/export/bootstrap3/export_list.html
@@ -4,7 +4,7 @@
{% load hq_shared_tags %}
{% load compress %}
-{% requirejs_main 'export/js/export_list_main' %}
+{% requirejs_main 'export/js/bootstrap3/export_list_main' %}
{% block page_title %}
{{ current_page.title }}
diff --git a/corehq/apps/export/templates/export/bootstrap5/export_list.html b/corehq/apps/export/templates/export/bootstrap5/export_list.html
index 570eab1b9c7f..dd3fa8a23086 100644
--- a/corehq/apps/export/templates/export/bootstrap5/export_list.html
+++ b/corehq/apps/export/templates/export/bootstrap5/export_list.html
@@ -4,7 +4,7 @@
{% load hq_shared_tags %}
{% load compress %}
-{% requirejs_main_b5 'export/js/export_list_main' %}
+{% requirejs_main_b5 'export/js/bootstrap5/export_list_main' %}
{% block page_title %}
{{ current_page.title }}
From c21c65f2ba141a0b7dbac40157d44db9eb4df8d3 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:32:36 +0000
Subject: [PATCH 23/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/customize_export_new.js, splitting templates"
---
.../{ => bootstrap3}/customize_export_new.js | 2 +-
.../js/bootstrap5/customize_export_new.js | 58 +++++++++++++++++++
.../bootstrap3/customize_export_new.html | 2 +-
.../bootstrap5/customize_export_new.html | 2 +-
4 files changed, 61 insertions(+), 3 deletions(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/customize_export_new.js (97%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js
diff --git a/corehq/apps/export/static/export/js/customize_export_new.js b/corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js
similarity index 97%
rename from corehq/apps/export/static/export/js/customize_export_new.js
rename to corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js
index ad36e80e2137..4d75247c1be3 100644
--- a/corehq/apps/export/static/export/js/customize_export_new.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js
@@ -1,4 +1,4 @@
-hqDefine('export/js/customize_export_new', [
+hqDefine('export/js/bootstrap3/customize_export_new', [
'jquery',
'knockout',
'hqwebapp/js/initial_page_data',
diff --git a/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js b/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js
new file mode 100644
index 000000000000..578d5c34e0f1
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js
@@ -0,0 +1,58 @@
+hqDefine('export/js/bootstrap5/customize_export_new', [
+ 'jquery',
+ 'knockout',
+ 'hqwebapp/js/initial_page_data',
+ 'export/js/models',
+ 'hqwebapp/js/toggles',
+ 'export/js/const',
+], function (
+ $,
+ ko,
+ initialPageData,
+ models,
+ toggles,
+ constants
+) {
+ $(function () {
+ var customExportView = new models.ExportInstance(
+ initialPageData.get('export_instance'),
+ {
+ saveUrl: initialPageData.get('full_path'),
+ hasExcelDashboardAccess: initialPageData.get('has_excel_dashboard_access'),
+ hasDailySavedAccess: initialPageData.get('has_daily_saved_export_access'),
+ formatOptions: initialPageData.get('format_options'),
+ sharingOptions: initialPageData.get('sharing_options'),
+ hasOtherOwner: initialPageData.get('has_other_owner'),
+ numberOfAppsToProcess: initialPageData.get('number_of_apps_to_process'),
+ geoProperties: initialPageData.get('geo_properties'),
+ }
+ );
+ initialPageData.registerUrl(
+ "build_schema", "/a/---/data/export/build_full_schema/"
+ );
+ $('#customize-export').koApplyBindings(customExportView);
+ $('.export-tooltip').tooltip(); /* todo B5: plugin:tooltip */
+
+ if (toggles.toggleEnabled('SUPPORT_GEO_JSON_EXPORT')) {
+ const exportFormat = initialPageData.get('export_instance').export_format;
+ if (exportFormat === constants.EXPORT_FORMATS.GEOJSON) {
+ $("#select-geo-property").show();
+ $("#split-multiselects-checkbox-div").hide();
+ $("#split-multiselects-checkbox").prop("checked", false);
+ }
+
+ $('#format-select').change(function () {
+ const selectedValue = $(this).val();
+ if (selectedValue === constants.EXPORT_FORMATS.GEOJSON) {
+ $("#select-geo-property").show();
+ // Hiding and unchecking this checkbox is a temporary measure
+ $("#split-multiselects-checkbox-div").hide();
+ $("#split-multiselects-checkbox").prop("checked", false);
+ } else {
+ $("#select-geo-property").hide();
+ $("#split-multiselects-checkbox-div").show();
+ }
+ });
+ }
+ });
+});
diff --git a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
index 44d3ea6dbfb9..f8fc37bbad52 100644
--- a/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap3/customize_export_new.html
@@ -2,7 +2,7 @@
{% load hq_shared_tags %}
{% load i18n %}
-{% requirejs_main 'export/js/customize_export_new' %}
+{% requirejs_main 'export/js/bootstrap3/customize_export_new' %}
{% block page_content %}
{% initial_page_data 'number_of_apps_to_process' number_of_apps_to_process %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
index 56a635d19428..a2d75ce4cba2 100644
--- a/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
+++ b/corehq/apps/export/templates/export/bootstrap5/customize_export_new.html
@@ -2,7 +2,7 @@
{% load hq_shared_tags %}
{% load i18n %}
-{% requirejs_main_b5 'export/js/customize_export_new' %}
+{% requirejs_main_b5 'export/js/bootstrap5/customize_export_new' %}
{% block page_content %}
{% initial_page_data 'number_of_apps_to_process' number_of_apps_to_process %}
From 8a2627f739cae65a62f69611d370bf851cf6fe07 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:32:48 +0000
Subject: [PATCH 24/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/incremental_export.js, splitting templates"
---
.../export/js/{ => bootstrap3}/incremental_export.js | 2 +-
.../static/export/js/bootstrap5/incremental_export.js | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/incremental_export.js (85%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/incremental_export.js
diff --git a/corehq/apps/export/static/export/js/incremental_export.js b/corehq/apps/export/static/export/js/bootstrap3/incremental_export.js
similarity index 85%
rename from corehq/apps/export/static/export/js/incremental_export.js
rename to corehq/apps/export/static/export/js/bootstrap3/incremental_export.js
index 491c5b25dabd..78fe7d70e808 100644
--- a/corehq/apps/export/static/export/js/incremental_export.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/incremental_export.js
@@ -1,4 +1,4 @@
-hqDefine('export/js/incremental_export', [
+hqDefine('export/js/bootstrap3/incremental_export', [
"jquery",
"hqwebapp/js/initial_page_data",
"hqwebapp/js/bootstrap3/crud_paginated_list_init",
diff --git a/corehq/apps/export/static/export/js/bootstrap5/incremental_export.js b/corehq/apps/export/static/export/js/bootstrap5/incremental_export.js
new file mode 100644
index 000000000000..954eb8a928e5
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/incremental_export.js
@@ -0,0 +1,10 @@
+hqDefine('export/js/bootstrap5/incremental_export', [
+ "jquery",
+ "hqwebapp/js/initial_page_data",
+ "hqwebapp/js/bootstrap5/crud_paginated_list_init",
+], function ($, initialPageData, CRUDPaginatedListInit) {
+ $(function () {
+ var viewModel = CRUDPaginatedListInit.paginatedListModel;
+ viewModel.reverse = initialPageData.reverse;
+ });
+});
From 6fcf9d64f981ef66665a502ea5215022a7a72bed Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:33:05 +0000
Subject: [PATCH 25/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/download_data_files.js, splitting templates"
---
.../{ => bootstrap3}/download_data_files.js | 2 +-
.../js/bootstrap5/download_data_files.js | 67 +++++++++++++++++++
.../bootstrap3/download_data_files.html | 2 +-
.../bootstrap5/download_data_files.html | 2 +-
4 files changed, 70 insertions(+), 3 deletions(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/download_data_files.js (97%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/download_data_files.js
diff --git a/corehq/apps/export/static/export/js/download_data_files.js b/corehq/apps/export/static/export/js/bootstrap3/download_data_files.js
similarity index 97%
rename from corehq/apps/export/static/export/js/download_data_files.js
rename to corehq/apps/export/static/export/js/bootstrap3/download_data_files.js
index 6452332a800c..ccea8464579d 100644
--- a/corehq/apps/export/static/export/js/download_data_files.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/download_data_files.js
@@ -1,4 +1,4 @@
-hqDefine("export/js/download_data_files",[
+hqDefine("export/js/bootstrap3/download_data_files",[
'jquery',
'hqwebapp/js/bootstrap3/alert_user',
'hqwebapp/js/initial_page_data',
diff --git a/corehq/apps/export/static/export/js/bootstrap5/download_data_files.js b/corehq/apps/export/static/export/js/bootstrap5/download_data_files.js
new file mode 100644
index 000000000000..b8a269f8988d
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/download_data_files.js
@@ -0,0 +1,67 @@
+hqDefine("export/js/bootstrap5/download_data_files",[
+ 'jquery',
+ 'hqwebapp/js/bootstrap5/alert_user',
+ 'hqwebapp/js/initial_page_data',
+ 'hqwebapp/js/assert_properties',
+], function ($, alertUserModule, initialPageData, assertProperties) {
+ var alertUser = alertUserModule.alert_user;
+ /**
+ * Copies the URL of a data file to the clipboard
+ *
+ * The function will first attempt to copy the URL to the clipboard without
+ * any further user interaction. If that fails, the user will be given a
+ * dialog box with the URL selected, and prompted to press Ctrl-C and Enter.
+ *
+ * @param url: The URL to be copied to the clipboard
+ * @param textareaElem: A hidden element containing the URL
+ */
+ var copyDataFileUrl = function () {
+ assertProperties.assertRequired($(this).data(), ['id', 'name']);
+
+ var url = window.location.origin + initialPageData.reverse('download_data_file',$(this).data("id"), $(this).data("name"));
+ var textareaElem = $('#url_'.concat($(this).data("id")));
+
+ var showCopyDialog = function () {
+ window.prompt(gettext("Copy to clipboard: Ctrl-C, Enter (Mac: Cmd-C, Enter)"), url);
+ };
+ try {
+ // Most browsers since Sept 2015
+ textareaElem.show();
+ textareaElem.select();
+ var copied = document.execCommand("copy");
+ textareaElem.hide();
+ if (copied) {
+ alertUser(gettext("Data file URL copied to clipboard."), "success", true);
+ } else {
+ showCopyDialog();
+ }
+ } catch (err) {
+ // Older browsers
+ showCopyDialog();
+ }
+ };
+
+ /**
+ * Makes an async DELETE request to url, and on success deletes rowElem.
+ *
+ * @param url: The URL to send the DELETE request to
+ * @param rowElem: The element of the data file to remove on successful deletion
+ */
+ var deleteDataFile = function () {
+ assertProperties.assertRequired($(this).data(), ['id','name']);
+ var url = initialPageData.reverse('download_data_file', $(this).data("id"), $(this).data("name"));
+ var rowElem = $('#row_'.concat($(this).data("id")));
+
+ $.ajax({
+ url: url,
+ type: "DELETE",
+ success: function () {
+ rowElem.remove();
+ alertUser(gettext("Data file deleted."), "success", true);
+ },
+ });
+ };
+ $(document).on('click', '.copy-data-file', copyDataFileUrl);
+ $(document).on('click', '.delete-data-file', deleteDataFile);
+
+});
diff --git a/corehq/apps/export/templates/export/bootstrap3/download_data_files.html b/corehq/apps/export/templates/export/bootstrap3/download_data_files.html
index d136dec339b8..49c4db1f2fc0 100644
--- a/corehq/apps/export/templates/export/bootstrap3/download_data_files.html
+++ b/corehq/apps/export/templates/export/bootstrap3/download_data_files.html
@@ -6,7 +6,7 @@
{% block title %}{% trans "Download Files" %}{% endblock %}
-{% requirejs_main 'export/js/download_data_files' %}
+{% requirejs_main 'export/js/bootstrap3/download_data_files' %}
{% block page_content %}
diff --git a/corehq/apps/export/templates/export/bootstrap5/download_data_files.html b/corehq/apps/export/templates/export/bootstrap5/download_data_files.html
index 485427672a07..666bed49502d 100644
--- a/corehq/apps/export/templates/export/bootstrap5/download_data_files.html
+++ b/corehq/apps/export/templates/export/bootstrap5/download_data_files.html
@@ -6,7 +6,7 @@
{% block title %}{% trans "Download Files" %}{% endblock %}
-{% requirejs_main_b5 'export/js/download_data_files' %}
+{% requirejs_main_b5 'export/js/bootstrap5/download_data_files' %}
{% block page_content %}
From 5672476da577f510dbefd42417f2d3fa4d100958 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:35:04 +0000
Subject: [PATCH 26/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/models.js, splitting templates"
---
.../js/bootstrap3/customize_export_new.js | 2 +-
.../export/js/{ => bootstrap3}/models.js | 2 +-
.../js/bootstrap5/customize_export_new.js | 2 +-
.../static/export/js/bootstrap5/models.js | 1017 +++++++++++++++++
.../static/export/spec/ExportColumn.spec.js | 2 +-
.../static/export/spec/ExportInstance.spec.js | 2 +-
.../static/export/spec/Exports.Utils.spec.js | 2 +-
.../templates/export/spec/ko/mocha.html | 2 +-
8 files changed, 1024 insertions(+), 7 deletions(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/models.js (99%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/models.js
diff --git a/corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js b/corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js
index 4d75247c1be3..e49e740b570a 100644
--- a/corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/customize_export_new.js
@@ -2,7 +2,7 @@ hqDefine('export/js/bootstrap3/customize_export_new', [
'jquery',
'knockout',
'hqwebapp/js/initial_page_data',
- 'export/js/models',
+ 'export/js/bootstrap3/models',
'hqwebapp/js/toggles',
'export/js/const',
], function (
diff --git a/corehq/apps/export/static/export/js/models.js b/corehq/apps/export/static/export/js/bootstrap3/models.js
similarity index 99%
rename from corehq/apps/export/static/export/js/models.js
rename to corehq/apps/export/static/export/js/bootstrap3/models.js
index d898e01d53bb..299e44238ba4 100644
--- a/corehq/apps/export/static/export/js/models.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/models.js
@@ -4,7 +4,7 @@
*
*/
-hqDefine('export/js/models', [
+hqDefine('export/js/bootstrap3/models', [
'jquery',
'knockout',
'underscore',
diff --git a/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js b/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js
index 578d5c34e0f1..5a0691ef04d5 100644
--- a/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js
+++ b/corehq/apps/export/static/export/js/bootstrap5/customize_export_new.js
@@ -2,7 +2,7 @@ hqDefine('export/js/bootstrap5/customize_export_new', [
'jquery',
'knockout',
'hqwebapp/js/initial_page_data',
- 'export/js/models',
+ 'export/js/bootstrap5/models',
'hqwebapp/js/toggles',
'export/js/const',
], function (
diff --git a/corehq/apps/export/static/export/js/bootstrap5/models.js b/corehq/apps/export/static/export/js/bootstrap5/models.js
new file mode 100644
index 000000000000..fe4d21588458
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/models.js
@@ -0,0 +1,1017 @@
+/**
+ * @file Defines all models for the export page. Models map to python models in
+ * corehq/apps/export/models/new.py
+ *
+ */
+
+hqDefine('export/js/bootstrap5/models', [
+ 'jquery',
+ 'knockout',
+ 'underscore',
+ 'hqwebapp/js/initial_page_data',
+ 'hqwebapp/js/toggles',
+ 'analytix/js/google',
+ 'analytix/js/kissmetrix',
+ 'export/js/const',
+ 'export/js/utils',
+ 'hqwebapp/js/bootstrap5/validators.ko', // needed for validation of customPathString
+ 'hqwebapp/js/bootstrap5/knockout_bindings.ko', // needed for multirow_sortable binding
+], function (
+ $,
+ ko,
+ _,
+ initialPageData,
+ toggles,
+ googleAnalytics,
+ kissmetricsAnalytics,
+ constants,
+ utils
+) {
+ /**
+ * readablePath
+ *
+ * Helper function that takes an array of PathNodes and converts them to a string dot path.
+ *
+ * @param {Array} pathNodes - An array of PathNodes to be converted to a string
+ * dot path.
+ * @returns {string} A string dot path that represents the array of PathNodes
+ */
+ var readablePath = function (pathNodes) {
+ return _.map(pathNodes, function (pathNode) {
+ var name = pathNode.name();
+ return ko.utils.unwrapObservable(pathNode.is_repeat) ? name + '[]' : name;
+ }).join('.');
+ };
+
+ /**
+ * customPathToNodes
+ *
+ * Helper function that takes a string path like form.meta.question and
+ * returns the equivalent path in an array of PathNodes.
+ *
+ * @param {string} customPathString - A string dot path to be converted
+ * to PathNodes.
+ * @returns {Array} Returns an array of PathNodes.
+ */
+ var customPathToNodes = function (customPathString) {
+ var parts = customPathString.split('.');
+ return _.map(parts, function (part) {
+ var isRepeat = !!part.match(/\[]$/);
+ if (isRepeat) {
+ part = part.slice(0, part.length - 2); // Remove the [] from the end of the path
+ }
+ return new PathNode({
+ name: part,
+ is_repeat: isRepeat,
+ doc_type: 'PathNode',
+ });
+ });
+ };
+
+ /**
+ * ExportInstance
+ * @class
+ *
+ * This is an instance of an export. It contains the tables to export
+ * and other presentation properties.
+ */
+ var ExportInstance = function (instanceJSON, options) {
+ options = options || {};
+ var self = this;
+ ko.mapping.fromJS(instanceJSON, ExportInstance.mapping, self);
+
+ self.geoProperties = options.geoProperties;
+ self.buildSchemaProgress = ko.observable(0);
+ self.showBuildSchemaProgressBar = ko.observable(false);
+ self.errorOnBuildSchema = ko.observable(false);
+ self.schemaProgressText = ko.observable(gettext('Process'));
+ self.numberOfAppsToProcess = options.numberOfAppsToProcess || 0;
+
+ // Constants and utils that the HTML template needs access to
+ self.splitTypes = {
+ multiselect: constants.MULTISELECT_SPLIT_TYPE,
+ plain: constants.PLAIN_SPLIT_TYPE,
+ userDefined: constants.USER_DEFINED_SPLIT_TYPES,
+ };
+ self.getTagCSSClass = utils.getTagCSSClass;
+ self.constants = constants;
+ if (self.include_errors) {
+ self.initiallyIncludeErrors = ko.observable(self.include_errors());
+ }
+
+ // Determines the state of the save. Used for controlling the presentation
+ // of the Save button.
+ self.saveState = ko.observable(constants.SAVE_STATES.READY);
+ self.saveStateReady = ko.computed(function () { return self.saveState() === constants.SAVE_STATES.READY; });
+ self.saveStateSaving = ko.computed(function () { return self.saveState() === constants.SAVE_STATES.SAVING; });
+ self.saveStateSuccess = ko.computed(function () { return self.saveState() === constants.SAVE_STATES.SUCCESS; });
+ self.saveStateError = ko.computed(function () { return self.saveState() === constants.SAVE_STATES.ERROR; });
+
+ // True if the form has no errors
+ self.isValid = ko.pureComputed(function () {
+ if (self.is_odata_config() && self.hasDuplicateColumnLabels()) {
+ return false;
+ }
+ if (!self.hasDailySavedAccess && self.is_daily_saved_export()) {
+ return false;
+ }
+ return true;
+ });
+
+ self.duplicateLabel = ko.observable();
+
+ self.hasDuplicateColumnLabels = ko.pureComputed(function () {
+ self.duplicateLabel('');
+ var hasDuplicates = false;
+ _.each(self.tables(), function (table) {
+ var labels = [];
+ _.each(table.columns(), function (column) {
+ if (column.selected() && labels.indexOf(column.label()) === -1) {
+ labels.push(column.label());
+ } else if (column.selected()) {
+ hasDuplicates = true;
+ self.duplicateLabel(column.label());
+ }
+ });
+ });
+ return hasDuplicates;
+ });
+
+ // The url to save the export to.
+ self.saveUrl = options.saveUrl;
+ self.hasExcelDashboardAccess = Boolean(options.hasExcelDashboardAccess);
+ self.hasDailySavedAccess = Boolean(options.hasDailySavedAccess);
+
+ self.formatOptions = options.formatOptions !== undefined ? options.formatOptions : _.map(constants.EXPORT_FORMATS, function (format) {
+ return format;
+ });
+
+ self.sharingOptions = options.sharingOptions !== undefined ? options.sharingOptions : _.map(constants.SHARING_OPTIONS, function (format) {
+ return format;
+ });
+
+ self.initialSharing = instanceJSON.sharing;
+ self.hasOtherOwner = options.hasOtherOwner;
+
+ // If any column has a deid transform, show deid column
+ self.isDeidColumnVisible = ko.observable(self.is_deidentified() || _.any(self.tables(), function (table) {
+ return table.selected() && _.any(table.columns(), function (column) {
+ return column.selected() && column.deid_transform();
+ });
+ }));
+
+ // Set column widths
+ self.questionColumnClass = ko.computed(function () {
+ var width = 6;
+ if (self.type && self.type() === 'case' && toggles.previewEnabled('SPLIT_MULTISELECT_CASE_EXPORT')) {
+ width--;
+ }
+ if (self.isDeidColumnVisible()) {
+ width--;
+ }
+ return "col-sm-" + width;
+ });
+ self.displayColumnClass = ko.computed(function () {
+ var width = 5;
+ if (self.type && self.type() === 'case' && toggles.previewEnabled('SPLIT_MULTISELECT_CASE_EXPORT')) {
+ width--;
+ }
+ if (self.isDeidColumnVisible()) {
+ width--;
+ }
+ return "col-sm-" + width;
+ });
+
+ self.hasHtmlFormat = ko.pureComputed(function () {
+ return this.export_format() === constants.EXPORT_FORMATS.HTML;
+ }, self);
+ self.hasDisallowedHtmlFormat = ko.pureComputed(function () {
+ return this.hasHtmlFormat() && !this.hasExcelDashboardAccess;
+ }, self);
+
+ self.hasCaseHistoryTable = ko.pureComputed(function () {
+ return _.any(self.tables(), function (table) {
+ if (table.label() !== 'Case History') {
+ return false;
+ }
+ return _.any(table.columns(), function (column) {
+ return column.selected();
+ });
+ });
+ });
+
+ self.export_format.subscribe(function (newFormat) {
+ // Selecting Excel Dashboard format automatically checks the daily saved export box
+ if (newFormat === constants.EXPORT_FORMATS.HTML) {
+ self.is_daily_saved_export(true);
+ } else {
+ if (!self.hasExcelDashboardAccess) {
+ self.is_daily_saved_export(false);
+ }
+ }
+ });
+ };
+
+ ExportInstance.prototype.onBeginSchemaBuild = function (exportInstance, e) {
+ var self = this,
+ $btn = $(e.currentTarget),
+ errorHandler,
+ successHandler,
+ buildSchemaUrl = initialPageData.reverse('build_schema', this.domain()),
+ identifier = ko.utils.unwrapObservable(this.case_type) || ko.utils.unwrapObservable(this.xmlns);
+
+ // We've already built the schema and now the user is clicking the button to refresh the page
+ if (this.buildSchemaProgress() === 100) {
+ // This param will let us know to automatically enable the filter after the page refreshes
+ let pageUrl = new URL(window.location.href);
+ pageUrl.searchParams.append('delete_filter_enabled', 'True');
+ window.location.href = pageUrl;
+ return;
+ }
+
+ this.showBuildSchemaProgressBar(true);
+ this.buildSchemaProgress(0);
+
+ self.schemaProgressText(gettext('Processing...'));
+ $btn.attr('disabled', true);
+ $btn.addClass('disabled');
+ $btn.addSpinnerToButton();
+
+ errorHandler = function () {
+ $btn.attr('disabled', false);
+ $btn.removeSpinnerFromButton();
+ $btn.removeClass('disabled');
+ self.errorOnBuildSchema(true);
+ self.schemaProgressText(gettext('Process'));
+ };
+
+ successHandler = function () {
+ $btn.removeSpinnerFromButton();
+ $btn.removeClass('disabled');
+ $btn.attr('disabled', false);
+ self.schemaProgressText(gettext('Refresh page'));
+ };
+
+ $.ajax({
+ url: buildSchemaUrl,
+ type: 'POST',
+ data: {
+ type: this.type(),
+ app_id: this.app_id(),
+ identifier: identifier,
+ },
+ dataType: 'json',
+ success: function (response) {
+ self.checkBuildSchemaProgress(response.download_id, successHandler, errorHandler);
+ },
+ error: errorHandler,
+ });
+ };
+
+ ExportInstance.prototype.checkBuildSchemaProgress = function (downloadId, successHandler, errorHandler) {
+ var self = this,
+ buildSchemaUrl = initialPageData.reverse('build_schema', this.domain());
+
+ $.ajax({
+ url: buildSchemaUrl,
+ type: 'GET',
+ data: {
+ download_id: downloadId,
+ },
+ dataType: 'json',
+ success: function (response) {
+ if (response.success) {
+ self.buildSchemaProgress(100);
+ self.showBuildSchemaProgressBar(false);
+ successHandler();
+ return;
+ }
+
+ if (response.failed) {
+ self.errorOnBuildSchema(true);
+ return;
+ }
+
+ self.buildSchemaProgress(response.progress.percent || 0);
+ if (response.not_started || response.progress.current === null ||
+ response.progress.current !== response.progress.total) {
+ window.setTimeout(
+ self.checkBuildSchemaProgress.bind(self, response.download_id, successHandler, errorHandler),
+ 2000
+ );
+ }
+ },
+ error: errorHandler,
+ });
+ };
+
+ ExportInstance.prototype.onLoadAllProperties = function () {
+ var pageUrl = new URL(window.location.href);
+ pageUrl.searchParams.append('load_deprecated', 'True');
+ window.location.href = pageUrl;
+ };
+
+ ExportInstance.prototype.getFormatOptionValues = function () {
+ return _.filter(constants.EXPORT_FORMATS, function (format) {
+ return this.formatOptions.indexOf(format) !== -1;
+ }, this);
+ };
+
+ ExportInstance.prototype.getFormatOptionText = function (format) {
+ if (format === constants.EXPORT_FORMATS.HTML) {
+ return gettext('Web Page (Excel Dashboards)');
+ } else if (format === constants.EXPORT_FORMATS.CSV) {
+ return gettext('CSV (Zip file)');
+ } else if (format === constants.EXPORT_FORMATS.XLS) {
+ return gettext('Excel (older versions)');
+ } else if (format === constants.EXPORT_FORMATS.XLSX) {
+ return gettext('Excel 2007+');
+ } else if (format === constants.EXPORT_FORMATS.GEOJSON) {
+ return gettext('GeoJSON');
+ }
+ };
+
+ ExportInstance.prototype.getSharingOptionValues = function () {
+ return _.filter(constants.SHARING_OPTIONS, function (format) {
+ return this.sharingOptions.indexOf(format) !== -1;
+ }, this);
+ };
+
+ ExportInstance.prototype.getSharingOptionText = function (format) {
+ if (format === constants.SHARING_OPTIONS.PRIVATE) {
+ return gettext('Private');
+ } else if (format === constants.SHARING_OPTIONS.EXPORT_ONLY) {
+ return gettext('Export Only');
+ } else if (format === constants.SHARING_OPTIONS.EDIT_AND_EXPORT) {
+ return gettext('Edit and Export');
+ }
+ };
+
+ ExportInstance.prototype.getSharingHelpText = gettext(
+ 'Private : Only you can edit and export.'
+ + ' Export Only : You can edit and export, other users can only export.'
+ + ' Edit and Export : All users can edit and export.'
+ );
+
+ /**
+ * isNew
+ *
+ * Determines if an export has been saved or not
+ *
+ * @returns {Boolean} - Returns true if the export has been saved, false otherwise.
+ */
+ ExportInstance.prototype.isNew = function () {
+ return !ko.utils.unwrapObservable(this._id);
+ };
+
+ ExportInstance.prototype.getSaveText = function () {
+ if (this.is_odata_config()) {
+ return gettext('Save');
+ }
+ return this.isNew() ? gettext('Create') : gettext('Save');
+ };
+
+ /**
+ * isReservedOdataColumn
+ *
+ * determines if a column is reserved for odata exports and cannot be deleted
+ *
+ * returns {Boolean}
+ */
+ ExportInstance.prototype.isReservedOdataColumn = function (column, tableId) {
+ if (!this.is_odata_config()) {
+ return false;
+ }
+ if (tableId === 0) {
+ return (column.formatProperty() === 'formid' || column.formatProperty() === 'caseid') && column.tags().indexOf('info') !== -1;
+ }
+ return column.formatProperty() === 'number';
+ };
+
+ /**
+ * save
+ *
+ * Saves an ExportInstance by serializing it and POSTing it
+ * to the server.
+ */
+ ExportInstance.prototype.save = function () {
+ var self = this,
+ serialized;
+
+ self.saveState(constants.SAVE_STATES.SAVING);
+ serialized = self.toJS();
+ $.post({
+ url: self.saveUrl,
+ data: JSON.stringify(serialized),
+ success: function (data) {
+ self.recordSaveAnalytics(function () {
+ self.saveState(constants.SAVE_STATES.SUCCESS);
+ utils.redirect(data.redirect);
+ });
+ },
+ error: function () {
+ self.saveState(constants.SAVE_STATES.ERROR);
+ },
+ });
+ };
+
+ /**
+ * recordSaveAnalytics
+ *
+ * Reports to analytics what type of configurations people are saving
+ * exports as.
+ *
+ * @param {function} callback - A function to be called after recording analytics.
+ */
+ ExportInstance.prototype.recordSaveAnalytics = function (callback) {
+ var analyticsAction = this.is_daily_saved_export() ? 'Saved' : 'Regular',
+ analyticsExportType = utils.capitalize(this.type()),
+ args,
+ eventCategory;
+
+ googleAnalytics.track.event("Create Export", analyticsExportType, analyticsAction);
+ if (this.export_format === constants.EXPORT_FORMATS.HTML) {
+ args = ["Create Export", analyticsExportType, 'Excel Dashboard', '', {}];
+ // If it's not new then we have to add the callback in to redirect
+ if (!this.isNew()) {
+ args.push(callback);
+ }
+ googleAnalytics.track.event.apply(null, args);
+ }
+ if (this.isNew()) {
+ eventCategory = constants.ANALYTICS_EVENT_CATEGORIES[this.type()];
+ googleAnalytics.track.event(eventCategory, 'Custom export creation', '');
+ kissmetricsAnalytics.track.event("Clicked 'Create' in export edit page", {}, callback);
+ } else if (this.export_format !== constants.EXPORT_FORMATS.HTML) {
+ callback();
+ }
+ };
+
+ ExportInstance.prototype.toggleShowDeleted = function (table) {
+ table.showDeleted(!table.showDeleted());
+
+ if (this.numberOfAppsToProcess > 0 && table.showDeleted()) {
+ $('#export-process-deleted-applications').modal('show'); /* todo B5: plugin:modal */
+ }
+ };
+
+ /**
+ * showDeidColumn
+ *
+ * Makse the deid column visible and scrolls the user back to the
+ * top of the export.
+ */
+ ExportInstance.prototype.showDeidColumn = function () {
+ utils.animateToEl('#field-select', function () {
+ this.isDeidColumnVisible(true);
+ }.bind(this));
+ };
+
+ ExportInstance.prototype.toJS = function () {
+ return ko.mapping.toJS(this, ExportInstance.mapping);
+ };
+
+ /**
+ * addUserDefinedTableConfiguration
+ *
+ * This will add a new table to the export configuration and seed it with
+ * one column, row number.
+ *
+ * @param {ExportInstance} instance
+ * @param {Object} e - The window's click event
+ */
+ ExportInstance.prototype.addUserDefinedTableConfiguration = function (instance, e) {
+ e.preventDefault();
+ instance.tables.push(new UserDefinedTableConfiguration({
+ selected: true,
+ doc_type: 'TableConfiguration',
+ label: 'Sheet',
+ is_user_defined: true,
+ path: [],
+ columns: [
+ {
+ doc_type: 'RowNumberColumn',
+ tags: ['row'],
+ item: {
+ doc_type: 'ExportItem',
+ path: [{
+ doc_type: 'PathNode',
+ name: 'number',
+ }],
+ },
+ selected: true,
+ is_advanced: false,
+ is_deprecated: false,
+ label: 'number',
+ deid_transform: null,
+ repeat: null,
+ },
+ ],
+ }));
+ };
+
+ ExportInstance.mapping = {
+ include: [
+ '_id',
+ 'name',
+ 'description',
+ 'sharing',
+ 'tables',
+ 'type',
+ 'export_format',
+ 'split_multiselects',
+ 'transform_dates',
+ 'format_data_in_excel',
+ 'include_errors',
+ 'is_deidentified',
+ 'domain',
+ 'app_id',
+ 'case_type',
+ 'xmlns',
+ 'is_daily_saved_export',
+ 'show_det_config_download',
+ 'selected_geo_property',
+ ],
+ tables: {
+ create: function (options) {
+ if (options.data.is_user_defined) {
+ return new UserDefinedTableConfiguration(options.data);
+ } else {
+ return new TableConfiguration(options.data);
+ }
+ },
+ },
+ };
+
+ /**
+ * TableConfiguration
+ * @class
+ *
+ * The TableConfiguration represents one excel sheet in an export.
+ * It contains a list of columns and other presentation properties
+ */
+ var TableConfiguration = function (tableJSON) {
+ var self = this;
+ const urlParams = new URLSearchParams(window.location.search);
+ // Whether or not to show advanced columns in the UI
+ self.showAdvanced = ko.observable(false);
+ self.showDeleted = ko.observable(urlParams.get('delete_filter_enabled') === 'True');
+
+ self.showDeprecated = ko.observable(urlParams.get('load_deprecated') === 'True');
+ ko.mapping.fromJS(tableJSON, TableConfiguration.mapping, self);
+ };
+
+ TableConfiguration.prototype.isVisible = function () {
+ // Not implemented
+ return true;
+ };
+
+ TableConfiguration.prototype.toggleShowAdvanced = function (table) {
+ table.showAdvanced(!table.showAdvanced());
+ };
+
+ TableConfiguration.prototype.toggleShowDeprecated = function (table) {
+ table.showDeprecated(!table.showDeprecated());
+
+ const queryString = window.location.search;
+ const urlParams = new URLSearchParams(queryString);
+ if (urlParams.get('load_deprecated') !== 'True' && table.showDeprecated()) {
+ $('#export-process-deprecated-properties').modal('show'); /* todo B5: plugin:modal */
+ }
+ };
+
+ TableConfiguration.prototype._select = function (select) {
+ _.each(this.columns(), function (column) {
+ column.selected(select && column.isVisible(this));
+ }.bind(this));
+ };
+
+ /**
+ * selectAll
+ *
+ * @param {TableConfiguration} table
+ *
+ * Selects all visible columns in the table.
+ */
+ TableConfiguration.prototype.selectAll = function (table) {
+ table._select(true);
+ };
+
+ /**
+ * selectNone
+ *
+ * @param {TableConfiguration} table
+ *
+ * Deselects all visible columns in the table.
+ */
+ TableConfiguration.prototype.selectNone = function (table) {
+ table._select(false);
+ };
+
+ /**
+ * useLabels
+ *
+ * @param {TableConfiguration} table
+ *
+ * Uses the question labels for the all the label values in the column.
+ */
+ TableConfiguration.prototype.useLabels = function (table) {
+ _.each(table.columns(), function (column) {
+ if (column.isQuestion() && !column.isUserDefined) {
+ column.label(column.item.label() || column.label());
+ }
+ });
+ };
+
+ /**
+ * useIds
+ *
+ * @param {TableConfiguration} table
+ *
+ * Uses the question ids for the all the label values in the column.
+ */
+ TableConfiguration.prototype.useIds = function (table) {
+ _.each(table.columns(), function (column) {
+ if (column.isQuestion() && !column.isUserDefined) {
+ column.label(column.item.readablePath() || column.label());
+ }
+ });
+ };
+
+ TableConfiguration.prototype.getColumn = function (path) {
+ return _.find(this.columns(), function (column) {
+ return readablePath(column.item.path()) === path;
+ });
+ };
+
+ TableConfiguration.prototype.addUserDefinedExportColumn = function (table, e) {
+ e.preventDefault();
+ table.columns.push(new UserDefinedExportColumn({
+ selected: true,
+ is_editable: true,
+ deid_transform: null,
+ doc_type: 'UserDefinedExportColumn',
+ label: '',
+ custom_path: [],
+ }));
+ };
+
+ TableConfiguration.mapping = {
+ include: ['name', 'path', 'columns', 'selected', 'label', 'is_deleted', 'doc_type', 'is_user_defined'],
+ columns: {
+ create: function (options) {
+ if (options.data.doc_type === 'UserDefinedExportColumn') {
+ return new UserDefinedExportColumn(options.data);
+ } else {
+ return new ExportColumn(options.data);
+ }
+ },
+ },
+ path: {
+ create: function (options) {
+ return new PathNode(options.data);
+ },
+ },
+ };
+
+ /**
+ * UserDefinedTableConfiguration
+ * @class
+ *
+ * This represents a table configuration that has been defined by the user. It
+ * is very similar to a TableConfiguration except that the user defines the
+ * path to where the new sheet should be.
+ *
+ * The customPathString for a table should always end in [] since a new export
+ * table should be an array.
+ *
+ * When specifying questions/properties in a user defined table, you'll need
+ * to include the base table path in the property. For example:
+ *
+ * table path: form.repeat[]
+ * question path: form.repeat[].question1
+ */
+ var UserDefinedTableConfiguration = function (tableJSON) {
+ var self = this;
+ ko.mapping.fromJS(tableJSON, TableConfiguration.mapping, self);
+ self.customPathString = ko.observable(readablePath(self.path()));
+ self.customPathString.extend({
+ required: true,
+ pattern: {
+ message: gettext('The table path should end with []'),
+ params: /^.*\[\]$/,
+ },
+ });
+
+ self.showAdvanced = ko.observable(false);
+ self.showDeleted = ko.observable(false);
+ self.showDeprecated = ko.observable(false);
+ self.customPathString.subscribe(self.onCustomPathChange.bind(self));
+ };
+ UserDefinedTableConfiguration.prototype = Object.create(TableConfiguration.prototype);
+
+ UserDefinedTableConfiguration.prototype.onCustomPathChange = function () {
+ var rowColumn,
+ nestedRepeatCount;
+ this.path(customPathToNodes(this.customPathString()));
+
+ // Update the rowColumn's repeat count by counting the number of
+ // repeats in the table path
+ rowColumn = this.getColumn('number');
+ if (rowColumn) {
+ nestedRepeatCount = _.filter(this.path(), function (node) { return node.is_repeat(); }).length;
+ rowColumn.repeat(nestedRepeatCount);
+ }
+ };
+
+ /**
+ * ExportColumn
+ * @class
+ *
+ * The model that represents a column in an export. Each column has a one-to-one
+ * mapping with an ExportItem. The column controls the presentation of that item.
+ */
+ var ExportColumn = function (columnJSON) {
+ var self = this;
+ ko.mapping.fromJS(columnJSON, ExportColumn.mapping, self);
+ // In some cases case property was having deleted tag present
+ // the function removes such exceptions on display
+ self.removeDeletedTagFromCaseName();
+ // showOptions is used a boolean for whether to show options for user defined option
+ // lists. This is used for the feature preview SPLIT_MULTISELECT_CASE_EXPORT
+ self.showOptions = ko.observable(false);
+ self.userDefinedOptionToAdd = ko.observable('');
+ self.isUserDefined = false;
+ self.selectedForSort = ko.observable(false);
+ };
+
+ /**
+ * isQuestion
+ *
+ * @returns {Boolean} - Returns true if the column is associated with a form question
+ * or a case property, false otherwise.
+ */
+ ExportColumn.prototype.isQuestion = function () {
+ var disallowedTags = ['info', 'case', 'server', 'row', 'app', 'stock'],
+ self = this;
+ return !_.any(disallowedTags, function (tag) { return _.include(self.tags(), tag); });
+ };
+
+
+ /**
+ * addUserDefinedOption
+ *
+ * This adds an options to the user defined options. This is used for the
+ * feature preview: SPLIT_MULTISELECT_CASE_EXPORT
+ */
+ ExportColumn.prototype.addUserDefinedOption = function () {
+ var option = this.userDefinedOptionToAdd();
+ if (option) {
+ this.user_defined_options.push(option);
+ }
+ this.userDefinedOptionToAdd('');
+ };
+
+ /**
+ * removeUserDefinedOption
+ *
+ * Removes a user defined option.
+ */
+ ExportColumn.prototype.removeUserDefinedOption = function (option) {
+ this.user_defined_options.remove(option);
+ };
+
+ /**
+ * formatProperty
+ *
+ * Formats a property/question for display.
+ *
+ * @returns {string} - Returns a string representation of the property/question
+ */
+ ExportColumn.prototype.formatProperty = function () {
+ if (this.tags().length !== 0) {
+ return this.label();
+ } else {
+ return _.map(this.item.path(), function (node) { return node.name(); }).join('.');
+ }
+ };
+
+ /**
+ * getDeidOptions
+ *
+ * @returns {Array} - A list of all deid option choices
+ */
+ ExportColumn.prototype.getDeidOptions = function () {
+ return _.map(constants.DEID_OPTIONS, function (value) { return value; });
+ };
+
+ /**
+ * getDeidOptionText
+ *
+ * @param {string} deidOption - A deid option
+ * @returns {string} - Given a deid option, returns the human readable label
+ */
+ ExportColumn.prototype.getDeidOptionText = function (deidOption) {
+ if (deidOption === constants.DEID_OPTIONS.ID) {
+ return gettext('Sensitive ID');
+ } else if (deidOption === constants.DEID_OPTIONS.DATE) {
+ return gettext('Sensitive Date');
+ } else if (deidOption === constants.DEID_OPTIONS.NONE) {
+ return gettext('None');
+ }
+ };
+
+ /**
+ * isVisible
+ *
+ * Determines whether the column is visible to the user.
+ *
+ * @returns {Boolean} - True if the column is visible false otherwise.
+ */
+ ExportColumn.prototype.isVisible = function (table) {
+ if (this.selected()) {
+ return true;
+ }
+
+ if (!this.is_advanced() && !this.is_deleted() && !this.is_deprecated()) {
+ return true;
+ }
+
+ if (table.showAdvanced() && this.is_advanced()) {
+ return true;
+ }
+
+ if (table.showDeleted() && this.is_deleted()) {
+ return true;
+ }
+
+ if (table.showDeprecated() && this.is_deprecated()) {
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * isCaseName
+ *
+ * Checks to see if the column is the name of the case property
+ *
+ * @returns {Boolean} - True if it is the case name property False otherwise.
+ */
+ ExportColumn.prototype.isCaseName = function () {
+ return this.item.isCaseName();
+ };
+
+ ExportColumn.prototype.translatedHelp = function () {
+ return gettext(this.help_text);
+ };
+
+ ExportColumn.prototype.isEditable = function () {
+ return false;
+ };
+
+ ExportColumn.prototype.removeDeletedTagFromCaseName = function () {
+ if (this.isCaseName() && this.is_deleted()) {
+ this.is_deleted(false);
+ var newTags = _.filter(this.tags(), function (tag) {
+ return tag !== "deleted";
+ });
+ this.tags(newTags);
+ }
+ };
+
+ ExportColumn.mapping = {
+ include: [
+ 'item',
+ 'label',
+ 'is_advanced',
+ 'is_deleted',
+ 'is_deprecated',
+ 'selected',
+ 'tags',
+ 'deid_transform',
+ 'help_text',
+ 'split_type',
+ 'user_defined_options',
+ ],
+ item: {
+ create: function (options) {
+ return new ExportItem(options.data);
+ },
+ },
+ };
+
+ /*
+ * UserDefinedExportColumn
+ *
+ * This model represents a column that a user has defined the path to the
+ * data within the form. It should only be needed for RemoteApps
+ */
+ var UserDefinedExportColumn = function (columnJSON) {
+ var self = this;
+ ko.mapping.fromJS(columnJSON, UserDefinedExportColumn.mapping, self);
+ self.showOptions = ko.observable(false);
+ self.isUserDefined = true;
+ self.customPathString = ko.observable(readablePath(self.custom_path())).extend({
+ required: true,
+ });
+ self.customPathString.subscribe(self.customPathToNodes.bind(self));
+ };
+ UserDefinedExportColumn.prototype = Object.create(ExportColumn.prototype);
+
+ UserDefinedExportColumn.prototype.isVisible = function () {
+ return true;
+ };
+
+ UserDefinedExportColumn.prototype.formatProperty = function () {
+ return _.map(this.custom_path(), function (node) { return node.name(); }).join('.');
+ };
+
+ UserDefinedExportColumn.prototype.isEditable = function () {
+ return this.is_editable();
+ };
+
+ UserDefinedExportColumn.prototype.customPathToNodes = function () {
+ this.custom_path(customPathToNodes(this.customPathString()));
+ };
+
+ UserDefinedExportColumn.mapping = {
+ include: [
+ 'selected',
+ 'deid_transform',
+ 'doc_type',
+ 'custom_path',
+ 'label',
+ 'is_editable',
+ ],
+ custom_path: {
+ create: function (options) {
+ return new PathNode(options.data);
+ },
+ },
+ };
+
+ /**
+ * ExportItem
+ * @class
+ *
+ * An item for export that is generated from the schema generation
+ */
+ var ExportItem = function (itemJSON) {
+ var self = this;
+ ko.mapping.fromJS(itemJSON, ExportItem.mapping, self);
+ };
+
+ /**
+ * isCaseName
+ *
+ * Checks to see if the item is the name of the case
+ *
+ * @returns {Boolean} - True if it is the case name property False otherwise.
+ */
+ ExportItem.prototype.isCaseName = function () {
+ try {
+ return this.path()[this.path().length - 1].name() === 'name';
+ } catch (error) {
+ return false;
+ }
+ };
+
+ ExportItem.prototype.readablePath = function () {
+ return readablePath(this.path());
+ };
+
+ ExportItem.mapping = {
+ include: ['path', 'label', 'tag'],
+ path: {
+ create: function (options) {
+ return new PathNode(options.data);
+ },
+ },
+ };
+
+ /**
+ * PathNode
+ * @class
+ *
+ * An node representing a portion of the path to item to export.
+ */
+ var PathNode = function (pathNodeJSON) {
+ ko.mapping.fromJS(pathNodeJSON, PathNode.mapping, this);
+ };
+
+ PathNode.mapping = {
+ include: ['name', 'is_repeat'],
+ };
+
+ return {
+ ExportInstance: ExportInstance,
+ ExportColumn: ExportColumn,
+ ExportItem: ExportItem,
+ PathNode: PathNode,
+ customPathToNodes: customPathToNodes, // exported for tests only
+ readablePath: readablePath, // exported for tests only
+ };
+
+});
diff --git a/corehq/apps/export/static/export/spec/ExportColumn.spec.js b/corehq/apps/export/static/export/spec/ExportColumn.spec.js
index 79626454de78..b1386e035ec6 100644
--- a/corehq/apps/export/static/export/spec/ExportColumn.spec.js
+++ b/corehq/apps/export/static/export/spec/ExportColumn.spec.js
@@ -1,7 +1,7 @@
/* eslint-env mocha */
hqDefine("export/spec/ExportColumn.spec", [
'underscore',
- 'export/js/models',
+ 'export/js/bootstrap3/models',
], function (
_,
viewModels
diff --git a/corehq/apps/export/static/export/spec/ExportInstance.spec.js b/corehq/apps/export/static/export/spec/ExportInstance.spec.js
index 574caa45040d..f9e4715bcb72 100644
--- a/corehq/apps/export/static/export/spec/ExportInstance.spec.js
+++ b/corehq/apps/export/static/export/spec/ExportInstance.spec.js
@@ -4,7 +4,7 @@ hqDefine("export/spec/ExportInstance.spec", [
'underscore',
'hqwebapp/js/initial_page_data',
'export/js/const',
- 'export/js/models',
+ 'export/js/bootstrap3/models',
'export/spec/data/export_instances',
], function (
$,
diff --git a/corehq/apps/export/static/export/spec/Exports.Utils.spec.js b/corehq/apps/export/static/export/spec/Exports.Utils.spec.js
index cf4c0380e48d..d29521ea8a6e 100644
--- a/corehq/apps/export/static/export/spec/Exports.Utils.spec.js
+++ b/corehq/apps/export/static/export/spec/Exports.Utils.spec.js
@@ -2,7 +2,7 @@
hqDefine("export/spec/Exports.Utils.spec", [
'underscore',
'export/js/const',
- 'export/js/models',
+ 'export/js/bootstrap3/models',
'export/js/utils',
], function (
_,
diff --git a/corehq/apps/export/templates/export/spec/ko/mocha.html b/corehq/apps/export/templates/export/spec/ko/mocha.html
index 339bfa57f4fa..e175822c4bc8 100644
--- a/corehq/apps/export/templates/export/spec/ko/mocha.html
+++ b/corehq/apps/export/templates/export/spec/ko/mocha.html
@@ -4,7 +4,7 @@
{% block dependencies %}
-
+
{% endblock %}
{% block mocha_tests %}
From 188fbb6852b34c2383077897dbc9f1e2b0cc69f2 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:35:14 +0000
Subject: [PATCH 27/35] "Bootstrap 5 Migration - initial auto-migration for
export/spec/ExportInstance.spec.js, splitting templates"
---
.../{ => bootstrap3}/ExportInstance.spec.js | 2 +-
.../spec/bootstrap5/ExportInstance.spec.js | 235 ++++++++++++++++++
.../templates/export/spec/ko/mocha.html | 2 +-
3 files changed, 237 insertions(+), 2 deletions(-)
rename corehq/apps/export/static/export/spec/{ => bootstrap3}/ExportInstance.spec.js (99%)
create mode 100644 corehq/apps/export/static/export/spec/bootstrap5/ExportInstance.spec.js
diff --git a/corehq/apps/export/static/export/spec/ExportInstance.spec.js b/corehq/apps/export/static/export/spec/bootstrap3/ExportInstance.spec.js
similarity index 99%
rename from corehq/apps/export/static/export/spec/ExportInstance.spec.js
rename to corehq/apps/export/static/export/spec/bootstrap3/ExportInstance.spec.js
index f9e4715bcb72..48c706811e13 100644
--- a/corehq/apps/export/static/export/spec/ExportInstance.spec.js
+++ b/corehq/apps/export/static/export/spec/bootstrap3/ExportInstance.spec.js
@@ -1,5 +1,5 @@
/* eslint-env mocha */
-hqDefine("export/spec/ExportInstance.spec", [
+hqDefine("export/spec/bootstrap3/ExportInstance.spec", [
'jquery',
'underscore',
'hqwebapp/js/initial_page_data',
diff --git a/corehq/apps/export/static/export/spec/bootstrap5/ExportInstance.spec.js b/corehq/apps/export/static/export/spec/bootstrap5/ExportInstance.spec.js
new file mode 100644
index 000000000000..bf958d333a03
--- /dev/null
+++ b/corehq/apps/export/static/export/spec/bootstrap5/ExportInstance.spec.js
@@ -0,0 +1,235 @@
+/* eslint-env mocha */
+hqDefine("export/spec/bootstrap5/ExportInstance.spec", [
+ 'jquery',
+ 'underscore',
+ 'hqwebapp/js/initial_page_data',
+ 'export/js/const',
+ 'export/js/bootstrap5/models',
+ 'export/spec/data/export_instances',
+], function (
+ $,
+ _,
+ initialPageData,
+ constants,
+ viewModels,
+ SampleExportInstances
+) {
+ describe('ExportInstance model', function () {
+ var basicFormExport, savedFormExport;
+ initialPageData.registerUrl(
+ "build_schema", "/a/---/data/export/build_full_schema/"
+ );
+ beforeEach(function () {
+ basicFormExport = _.clone(SampleExportInstances.basic, { saveUrl: 'http://saveurl/' });
+ savedFormExport = _.clone(SampleExportInstances.saved, { saveUrl: 'http://saveurl/' });
+ });
+
+ it('Should create an instance from JSON', function () {
+ var instance = new viewModels.ExportInstance(basicFormExport);
+
+ assert.equal(instance.tables().length, 1);
+
+ var table = instance.tables()[0];
+ assert.equal(table.columns().length, 2);
+
+ _.each(table.columns(), function (column) {
+ assert.ok(column.item);
+ assert.isTrue(column instanceof viewModels.ExportColumn);
+ assert.isDefined(column.show());
+ assert.isDefined(column.selected());
+ assert.isDefined(column.label());
+
+ var item = column.item;
+ assert.isTrue(item instanceof viewModels.ExportItem);
+ assert.isDefined(item.label);
+ assert.isDefined(item.path);
+ assert.isDefined(item.tag);
+ });
+ });
+
+ it('Should serialize an instance into JS object', function () {
+ var instance = new viewModels.ExportInstance(basicFormExport);
+ var obj = instance.toJS();
+ assert.equal(obj.tables.length, 1);
+
+ var table = obj.tables[0];
+ assert.equal(table.columns.length, 2);
+
+ _.each(table.columns, function (column) {
+ assert.ok(column.item);
+ assert.isFalse(column instanceof viewModels.ExportColumn);
+ assert.isDefined(column.show);
+ assert.isDefined(column.selected);
+ assert.isDefined(column.label);
+
+ var item = column.item;
+ assert.isFalse(item instanceof viewModels.ExportItem);
+ assert.isDefined(item.label);
+ assert.isDefined(item.path);
+ assert.isDefined(item.tag);
+ });
+ });
+ describe('#isNew', function () {
+ var instance, instanceSaved;
+ beforeEach(function () {
+ instance = new viewModels.ExportInstance(basicFormExport);
+ instanceSaved = new viewModels.ExportInstance(savedFormExport);
+ });
+
+ it('should correctly determine if instance is new', function () {
+ assert.isTrue(instance.isNew());
+ });
+
+ it('should correctly determine if instance is new', function () {
+ assert.isFalse(instanceSaved.isNew());
+ });
+
+ });
+
+ describe('#onBeginSchemaBuild', function () {
+ var instance;
+ beforeEach(function () {
+ instance = new viewModels.ExportInstance(basicFormExport);
+ sinon.spy($, "ajax");
+ });
+
+ afterEach(function () {
+ $.ajax.restore();
+ });
+
+ it('should trigger build', function () {
+ instance.onBeginSchemaBuild(instance, {});
+
+ assert.equal(instance.buildSchemaProgress(), 0);
+ assert.isTrue(instance.showBuildSchemaProgressBar());
+ assert.isTrue($.ajax.called);
+ });
+
+ });
+
+ describe('#checkBuildSchemaProgress', function () {
+ var instance,
+ requests,
+ clock,
+ xhr;
+ beforeEach(function () {
+ requests = [];
+ instance = new viewModels.ExportInstance(basicFormExport);
+ clock = sinon.useFakeTimers();
+ xhr = sinon.useFakeXMLHttpRequest();
+ xhr.onCreate = function (xhr) {
+ requests.push(xhr);
+ };
+ });
+
+ afterEach(function () {
+ xhr.restore();
+ clock.restore();
+ });
+
+ it('successfully check for pending build', function () {
+ var successSpy = sinon.spy(),
+ response = {
+ success: false,
+ failed: false,
+ not_started: false,
+ progress: {
+ percent: 50,
+ current: 50,
+ total: 100,
+ },
+ },
+ successResponse = {
+ success: true,
+ failed: false,
+ progress: {},
+ };
+ instance.checkBuildSchemaProgress('123', successSpy, sinon.spy());
+
+ assert.equal(requests.length, 1);
+ // Respond with pending build
+ requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(response)
+ );
+
+ // Should not have queued up a new request yet
+ assert.equal(requests.length, 1);
+ assert.equal(instance.buildSchemaProgress(), 50);
+
+ // Fast forward time, should trigger another request
+ clock.tick(2001);
+ assert.equal(requests.length, 2);
+ requests[1].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(successResponse)
+ );
+
+ assert.isTrue(successSpy.called);
+ assert.equal(instance.buildSchemaProgress(), 100);
+ assert.isFalse(instance.showBuildSchemaProgressBar());
+ });
+ });
+
+ describe('#save', function () {
+ var server,
+ recordSaveAnalyticsSpy,
+ instance;
+
+ beforeEach(function () {
+ instance = new viewModels.ExportInstance(basicFormExport);
+ recordSaveAnalyticsSpy = sinon.spy();
+ server = sinon.fakeServer.create();
+
+ sinon.stub(instance, 'recordSaveAnalytics', recordSaveAnalyticsSpy);
+ });
+
+ afterEach(function () {
+ server.restore();
+ instance.recordSaveAnalytics.restore();
+ });
+
+ it('Should save a model', function () {
+ server.respondWith(
+ "POST",
+ instance.saveUrl,
+ [
+ 200,
+ { "Content-Type": "application/json" },
+ '{ "redirect": "http://dummy/"}',
+ ]
+ );
+
+ assert.equal(instance.saveState(), constants.SAVE_STATES.READY);
+ instance.save();
+
+ assert.equal(instance.saveState(), constants.SAVE_STATES.SAVING);
+ server.respond();
+
+ assert.isTrue(recordSaveAnalyticsSpy.called);
+ });
+
+ it('Should crash on saving export', function () {
+ server.respondWith(
+ "POST",
+ instance.saveUrl,
+ [
+ 500,
+ { "Content-Type": "application/json" },
+ '{ "status": "fail" }',
+ ]
+ );
+ instance.save();
+
+ assert.equal(instance.saveState(), constants.SAVE_STATES.SAVING);
+ server.respond();
+
+ assert.equal(instance.saveState(), constants.SAVE_STATES.ERROR);
+ assert.isFalse(recordSaveAnalyticsSpy.called);
+ });
+
+ });
+ });
+});
diff --git a/corehq/apps/export/templates/export/spec/ko/mocha.html b/corehq/apps/export/templates/export/spec/ko/mocha.html
index e175822c4bc8..a669d2371eba 100644
--- a/corehq/apps/export/templates/export/spec/ko/mocha.html
+++ b/corehq/apps/export/templates/export/spec/ko/mocha.html
@@ -9,7 +9,7 @@
{% block mocha_tests %}
-
+
{% endblock %}
From 20cf4f98a4fc369992e5074ae6a8f56eb3cf5383 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:35:26 +0000
Subject: [PATCH 28/35] "Bootstrap 5 Migration - initial auto-migration for
export/spec/Exports.Utils.spec.js, splitting templates"
---
.../{ => bootstrap3}/Exports.Utils.spec.js | 2 +-
.../spec/bootstrap5/Exports.Utils.spec.js | 74 +++++++++++++++++++
.../templates/export/spec/ko/mocha.html | 2 +-
3 files changed, 76 insertions(+), 2 deletions(-)
rename corehq/apps/export/static/export/spec/{ => bootstrap3}/Exports.Utils.spec.js (98%)
create mode 100644 corehq/apps/export/static/export/spec/bootstrap5/Exports.Utils.spec.js
diff --git a/corehq/apps/export/static/export/spec/Exports.Utils.spec.js b/corehq/apps/export/static/export/spec/bootstrap3/Exports.Utils.spec.js
similarity index 98%
rename from corehq/apps/export/static/export/spec/Exports.Utils.spec.js
rename to corehq/apps/export/static/export/spec/bootstrap3/Exports.Utils.spec.js
index d29521ea8a6e..1a251981a4b2 100644
--- a/corehq/apps/export/static/export/spec/Exports.Utils.spec.js
+++ b/corehq/apps/export/static/export/spec/bootstrap3/Exports.Utils.spec.js
@@ -1,5 +1,5 @@
/* eslint-env mocha */
-hqDefine("export/spec/Exports.Utils.spec", [
+hqDefine("export/spec/bootstrap3/Exports.Utils.spec", [
'underscore',
'export/js/const',
'export/js/bootstrap3/models',
diff --git a/corehq/apps/export/static/export/spec/bootstrap5/Exports.Utils.spec.js b/corehq/apps/export/static/export/spec/bootstrap5/Exports.Utils.spec.js
new file mode 100644
index 000000000000..8a9d0174c4a2
--- /dev/null
+++ b/corehq/apps/export/static/export/spec/bootstrap5/Exports.Utils.spec.js
@@ -0,0 +1,74 @@
+/* eslint-env mocha */
+hqDefine("export/spec/bootstrap5/Exports.Utils.spec", [
+ 'underscore',
+ 'export/js/const',
+ 'export/js/bootstrap5/models',
+ 'export/js/utils',
+], function (
+ _,
+ constants,
+ models,
+ utils
+) {
+ describe('Export Utility functions', function () {
+ describe('#getTagCSSClass', function () {
+ it('Should get regular tag class', function () {
+ var cls = utils.getTagCSSClass('random-tag');
+ assert.equal(cls, 'label label-default');
+ });
+
+ it('Should get warning tag class', function () {
+ var cls = utils.getTagCSSClass(constants.TAG_DELETED);
+ assert.equal(cls, 'label label-warning');
+ });
+ });
+
+ describe('#readablePath', function () {
+ it('Should convert an anrray of PathNode to a dot path', function () {
+ var nodes = [
+ new models.PathNode({ name: 'form', is_repeat: false, doc_type: 'PathNode' }),
+ new models.PathNode({ name: 'photo', is_repeat: false, doc_type: 'PathNode' }),
+ ];
+ assert.equal(models.readablePath(nodes), 'form.photo');
+ });
+
+ it('Should convert an array of PathNode to a dot path with repeats', function () {
+ var nodes = [
+ new models.PathNode({ name: 'form', is_repeat: false, doc_type: 'PathNode' }),
+ new models.PathNode({ name: 'repeat', is_repeat: true, doc_type: 'PathNode' }),
+ ];
+ assert.equal(models.readablePath(nodes), 'form.repeat[]');
+ });
+ });
+
+ describe('#customPathToNodes', function () {
+ it('Should convert a string path to PathNodes', function () {
+ var customPath = 'form.photo';
+ var nodes = models.customPathToNodes(customPath);
+
+ assert.equal(nodes.length, 2);
+ assert.isTrue(_.all(nodes, function (n) { return n instanceof models.PathNode; }));
+
+ assert.equal(nodes[0].name(), 'form');
+ assert.isFalse(nodes[0].is_repeat());
+
+ assert.equal(nodes[1].name(), 'photo');
+ assert.isFalse(nodes[1].is_repeat());
+ });
+
+ it('Should convert a string path to PathNodes with repeats', function () {
+ var customPath = 'form.repeat[]';
+ var nodes = models.customPathToNodes(customPath);
+
+ assert.equal(nodes.length, 2);
+ assert.isTrue(_.all(nodes, function (n) { return n instanceof models.PathNode; }));
+
+ assert.equal(nodes[0].name(), 'form');
+ assert.isFalse(nodes[0].is_repeat());
+
+ assert.equal(nodes[1].name(), 'repeat');
+ assert.isTrue(nodes[1].is_repeat());
+ });
+ });
+ });
+});
diff --git a/corehq/apps/export/templates/export/spec/ko/mocha.html b/corehq/apps/export/templates/export/spec/ko/mocha.html
index a669d2371eba..75aca65e9973 100644
--- a/corehq/apps/export/templates/export/spec/ko/mocha.html
+++ b/corehq/apps/export/templates/export/spec/ko/mocha.html
@@ -11,5 +11,5 @@
-
+
{% endblock %}
From 65f3c7f8406fc186ae917b421443a6083845ae7b Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:36:03 +0000
Subject: [PATCH 29/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/export_list.js, splitting templates"
---
.../export/js/{ => bootstrap3}/export_list.js | 2 +-
.../export/js/bootstrap3/export_list_main.js | 2 +-
.../export/js/bootstrap5/export_list.js | 701 ++++++++++++++++++
.../export/js/bootstrap5/export_list_main.js | 2 +-
4 files changed, 704 insertions(+), 3 deletions(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/export_list.js (99%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/export_list.js
diff --git a/corehq/apps/export/static/export/js/export_list.js b/corehq/apps/export/static/export/js/bootstrap3/export_list.js
similarity index 99%
rename from corehq/apps/export/static/export/js/export_list.js
rename to corehq/apps/export/static/export/js/bootstrap3/export_list.js
index a56d048268d7..18d04c44d829 100644
--- a/corehq/apps/export/static/export/js/export_list.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/export_list.js
@@ -11,7 +11,7 @@
* bulk export, which is a page-level action (you can select exports across panels to bulk export).
* It also controls filter editing (for daily saved / dashboard feeds).
*/
-hqDefine("export/js/export_list", [
+hqDefine("export/js/bootstrap3/export_list", [
'jquery',
'knockout',
'underscore',
diff --git a/corehq/apps/export/static/export/js/bootstrap3/export_list_main.js b/corehq/apps/export/static/export/js/bootstrap3/export_list_main.js
index 143ad6769f71..401f8c07344d 100644
--- a/corehq/apps/export/static/export/js/bootstrap3/export_list_main.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/export_list_main.js
@@ -4,7 +4,7 @@ hqDefine("export/js/bootstrap3/export_list_main", [
'analytix/js/kissmetrix',
'hqwebapp/js/bootstrap3/main',
'export/js/create_export',
- 'export/js/export_list',
+ 'export/js/bootstrap3/export_list',
'hqwebapp/js/select_2_ajax_widget', // for case owner & user filters in DashboardFeedFilterForm
], function (
$,
diff --git a/corehq/apps/export/static/export/js/bootstrap5/export_list.js b/corehq/apps/export/static/export/js/bootstrap5/export_list.js
new file mode 100644
index 000000000000..adfad99ce8e5
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/export_list.js
@@ -0,0 +1,701 @@
+/**
+ * This module contains the knockout models that control the "list" part of the exports list.
+ * This serves all export types: form vs case and exports vs daily saved vs dashboard feeds.
+ * It does NOT contain the logic for adding a new export, which is also done on the export list page.
+ *
+ * There are three models in this file:
+ * exportModel represents an individual export: name, description, case type, etc.
+ * exportPanelModel represents a set of exports. Each of these is displayed in the UI as
+ * a panel with independent pagination.
+ * exportListModel represents the entire page. It contains one or more panels. It controls
+ * bulk export, which is a page-level action (you can select exports across panels to bulk export).
+ * It also controls filter editing (for daily saved / dashboard feeds).
+ */
+hqDefine("export/js/bootstrap5/export_list", [
+ 'jquery',
+ 'knockout',
+ 'underscore',
+ 'hqwebapp/js/assert_properties',
+ 'clipboard/dist/clipboard',
+ 'analytix/js/google',
+ 'analytix/js/kissmetrix',
+ 'export/js/utils',
+ 'hqwebapp/js/bootstrap5/validators.ko', // needed for validation of startDate and endDate
+ 'hqwebapp/js/bootstrap5/components.ko', // pagination & feedback widget
+ 'select2/dist/js/select2.full.min',
+], function (
+ $,
+ ko,
+ _,
+ assertProperties,
+ Clipboard,
+ googleAnalytics,
+ kissmetricsAnalytics,
+ utils
+) {
+ var exportModel = function (options, pageOptions) {
+ assertProperties.assert(pageOptions, ['is_deid', 'is_odata', 'model_type', 'urls']);
+
+ _.each(['isAutoRebuildEnabled', 'isDailySaved', 'isFeed', 'isOData'], function (key) {
+ options[key] = options[key] || false;
+ });
+ options.formname = options.formname || '';
+ assertProperties.assert(options, [
+ 'addedToBulk',
+ 'additionalODataUrls',
+ 'can_edit',
+ 'deleteUrl',
+ 'description',
+ 'domain',
+ 'downloadUrl',
+ 'showDetDownload',
+ 'detSchemaUrl',
+ 'editUrl',
+ 'emailedExport',
+ 'exportType',
+ 'filters',
+ 'formname',
+ 'id',
+ 'isDeid',
+ 'lastBuildDuration',
+ 'name',
+ 'odataUrl',
+ 'owner_username',
+ 'sharing',
+ 'type',
+ ], [
+ 'case_type',
+ 'is_case_type_deprecated',
+ 'isAutoRebuildEnabled',
+ 'isDailySaved',
+ 'isFeed',
+ 'isOData',
+ 'editNameUrl',
+ 'editDescriptionUrl',
+ ]);
+ assertProperties.assert(pageOptions.urls, ['poll', 'toggleEnabled', 'update']);
+
+ var self = ko.mapping.fromJS(options);
+
+ self.showSavedFilters = !!options.filters;
+ if (self.showSavedFilters) {
+ // un-knockoutify case and form filter objects
+ self.filters.emwf_case_filter(options.filters.emwf_case_filter);
+ self.filters.emwf_form_filter(options.filters.emwf_form_filter);
+ }
+
+ self.hasEmailedExport = !!options.emailedExport;
+ if (self.hasEmailedExport) {
+ self.emailedExport = emailedExportModel(options.emailedExport, pageOptions, self.id(), self.exportType());
+ if (options.isFeed) {
+ self.feedUrl = exportFeedUrl(options.emailedExport.fileData.downloadUrl);
+ }
+ }
+
+ if (options.editNameUrl) {
+ self.editNameUrl = options.editNameUrl;
+ }
+ if (options.editDescriptionUrl) {
+ self.editDescriptionUrl = options.editDescriptionUrl;
+ }
+
+ if (options.isOData) {
+ self.odataFeedUrl = exportFeedUrl(options.odataUrl);
+ self.odataAdditionalFeedUrls = ko.observableArray(_.map(options.additionalODataUrls, function (urlData) {
+ urlData.url = exportFeedUrl(urlData.url);
+ return urlData;
+ }));
+ self.hasAdditionalODataFeeds = ko.computed(function () {
+ return self.odataAdditionalFeedUrls().length > 0;
+ });
+ self.sendAnalyticsOpenAdditionalFeeds = function () {
+ if (options.exportType === 'form') {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked Repeat Group Feeds");
+ } else {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked Parent Feeds");
+ }
+ };
+ self.sendAnalyticsCloseAdditionalFeeds = function () {
+ var eventData = {
+ "Number of feeds": self.odataAdditionalFeedUrls().length,
+ };
+ if (options.exportType === 'form') {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked Close on Repeat Group Feeds modal", eventData);
+ } else {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked Close on Parent Feeds modal", eventData);
+ }
+ };
+ }
+
+ self.editExport = function () {
+ if (options.isOData) {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked Copy OData Feed Link");
+ setTimeout(function () {
+ window.location.href = self.editUrl();
+ }, 250);
+ } else {
+ window.location.href = self.editUrl();
+ }
+ };
+
+ self.deleteExport = function (observable, event) {
+ if (options.isOData) {
+ kissmetricsAnalytics.track.event("[BI Integration] Deleted Feed");
+ setTimeout(function () {
+ $(event.currentTarget).closest('form').submit();
+ }, 250);
+ } else {
+ $(event.currentTarget).closest('form').submit();
+ }
+ };
+
+ self.isLocationSafeForUser = function () {
+ return !self.hasEmailedExport || self.emailedExport.isLocationSafeForUser();
+ };
+
+ self.downloadRequested = function (model, e) {
+ var $btn = $(e.target);
+ $btn.addClass('disabled');
+ $btn.text(gettext('Download Requested'));
+ return true; // allow default click action to process so file is downloaded
+ };
+
+ self.updateDisabledState = function (model, e) {
+ var $button = $(e.currentTarget);
+ $button.disableButton();
+ $.ajax({
+ method: 'POST',
+ url: pageOptions.urls.toggleEnabled,
+ data: {
+ export_id: self.id(),
+ is_auto_rebuild_enabled: self.isAutoRebuildEnabled(),
+ is_deid: pageOptions.is_deid,
+ is_odata: pageOptions.is_odata,
+ model_type: pageOptions.model_type,
+ },
+ success: function (data) {
+ if (data.success) {
+ var exportType = utils.capitalize(self.exportType());
+ var event = (self.isAutoRebuildEnabled() ? "Disable" : "Enable") + " Saved Export";
+ googleAnalytics.track.event(exportType + " Exports", event, "Saved");
+ self.isAutoRebuildEnabled(data.isAutoRebuildEnabled);
+ }
+ $button.enableButton();
+ $('#modalEnableDisableAutoRefresh-' + self.id() + '-' + self.emailedExport.groupId()).modal('hide'); /* todo B5: plugin:modal */
+ },
+ });
+ };
+
+ return self;
+ };
+
+ var exportFeedUrl = function (url) {
+ var self = {};
+
+ self.url = ko.observable(url);
+
+ self.showLink = ko.observable(false);
+
+ self.copyLinkRequested = function (model, e) {
+ self.showLink(true);
+ var clipboard = new Clipboard(e.target, {
+ target: function (trigger) {
+ return trigger.nextElementSibling;
+ },
+ });
+ clipboard.onClick(e);
+ clipboard.destroy();
+ };
+
+ return self;
+ };
+
+ var emailedExportModel = function (emailedExportOptions, pageOptions, exportId, exportType) {
+ var self = ko.mapping.fromJS(emailedExportOptions);
+ self.prepareExportError = ko.observable('');
+
+ self.justUpdated = ko.computed(function () {
+ if (self.taskStatus === undefined) {
+ return false;
+ }
+ return self.taskStatus.justFinished() && self.taskStatus.success();
+ });
+
+ self.canUpdateData = ko.computed(function () {
+ return (self.prepareExportError() ||
+ !(self.updatingData() || self.taskStatus && self.taskStatus.started()));
+ });
+
+ self.pollProgressBar = function () {
+ self.updatingData(false);
+ self.taskStatus.percentComplete();
+ self.taskStatus.started(true);
+ self.taskStatus.success(false);
+ self.taskStatus.failed(null);
+ var tick = function () {
+ $.ajax({
+ method: 'GET',
+ url: pageOptions.urls.poll,
+ data: {
+ export_instance_id: exportId,
+ is_deid: pageOptions.is_deid,
+ model_type: pageOptions.model_type,
+ },
+ success: function (data) {
+ self.taskStatus.percentComplete(data.taskStatus.percentComplete);
+ self.taskStatus.started(data.taskStatus.started);
+ self.taskStatus.success(data.taskStatus.success);
+ self.taskStatus.failed(data.taskStatus.failed);
+ self.taskStatus.justFinished(data.taskStatus.justFinished);
+ if (!data.taskStatus.success && !data.taskStatus.failed) {
+ // The first few ticks don't yet register the task
+ self.taskStatus.started(true);
+ setTimeout(tick, 1500);
+ } else {
+ self.taskStatus.justFinished(true);
+ }
+ },
+ });
+ };
+ tick();
+ };
+
+ self.updateData = function () {
+ $('#modalRefreshExportConfirm-' + exportId + '-' + self.groupId()).modal('hide'); /* todo B5: plugin:modal */
+ self.updatingData(true);
+ $.ajax({
+ method: 'POST',
+ url: pageOptions.urls.update,
+ data: {
+ export_id: exportId,
+ is_deid: pageOptions.is_deid,
+ is_odata: pageOptions.is_odata,
+ model_type: pageOptions.model_type,
+ },
+ success: function (data) {
+ if (data.success) {
+ var exportType_ = utils.capitalize(exportType);
+ googleAnalytics.track.event(exportType_ + " Exports", "Update Saved Export", "Saved");
+ self.pollProgressBar();
+ } else {
+ self.prepareExportError(data.error);
+ }
+ },
+ });
+ };
+
+ return self;
+ };
+
+ var exportPanelModel = function (options) {
+ assertProperties.assert(options, [
+ 'header',
+ 'isDailySavedExport',
+ 'isDeid',
+ 'isFeed',
+ 'isOData',
+ 'modelType',
+ 'myExports',
+ 'showOwnership',
+ 'urls',
+ 'exportOwnershipEnabled',
+ ]);
+
+ var self = _.extend({}, options);
+
+ // Observable array because it'll be loaded via ajax
+ self.exports = ko.observableArray([]);
+
+ // Loading/error handling UI
+ self.loadingErrorMessage = ko.observable('');
+ self.isBulkDeleting = ko.observable(false);
+ self.isLoadingPanel = ko.observable(true);
+ self.isLoadingPage = ko.observable(false);
+ self.hasError = ko.observable(false);
+ self.showError = ko.computed(function () {
+ return !self.isLoadingPanel() && self.hasError();
+ });
+ self.showEmpty = ko.computed(function () {
+ return !self.isLoadingPanel() && !self.hasError() && !self.exports().length;
+ });
+ self.hasData = ko.computed(function () {
+ return !self.isLoadingPanel() && !self.hasError() && self.exports().length;
+ });
+
+ //Bulk Action selection
+ self.selectAll = function () {
+ _.each(self.exports(), function (e) { e.addedToBulk(true); });
+ };
+ self.selectNone = function () {
+ _.each(self.exports(), function (e) { e.addedToBulk(false); });
+ };
+
+ self.totalItems = ko.observable(0);
+ self.itemsPerPage = ko.observable();
+ self.goToPage = function (page) {
+ if (self.hasData()) {
+ self.fetchPage(page);
+ }
+ };
+ self.fetchPage = function (page) {
+ self.isLoadingPage(true);
+ $.ajax({
+ method: 'GET',
+ url: self.urls.getExportsPage,
+ data: {
+ is_deid: self.isDeid,
+ is_odata: self.isOData ? 1 : 0,
+ model_type: self.modelType,
+ is_daily_saved_export: self.isDailySavedExport ? 1 : 0,
+ is_feed: self.isFeed ? 1 : 0,
+ my_exports: self.myExports ? 1 : 0,
+ page: page,
+ limit: self.itemsPerPage(),
+ },
+ success: function (data) {
+ self.isLoadingPanel(false);
+ self.isLoadingPage(false);
+ self.totalItems(data.total);
+
+ self.exports(_.map(data.exports, function (e) {
+ return exportModel(e, {
+ is_deid: self.isDeid,
+ is_odata: self.isOData,
+ model_type: self.modelType,
+ urls: _.pick(self.urls, 'poll', 'toggleEnabled', 'update'),
+ });
+ }));
+
+ // Set up progress bar polling for any exports with email tasks running
+ _.each(self.exports(), function (exp) {
+ if (exp.hasEmailedExport && exp.emailedExport.taskStatus && exp.emailedExport.taskStatus.started()) {
+ exp.emailedExport.pollProgressBar();
+ }
+ });
+ },
+ error: function () {
+ self.isLoadingPanel(false);
+ self.hasError(true);
+ },
+ });
+ };
+
+ self.onPaginationLoad = function () {
+ self.fetchPage(1);
+ };
+
+ return self;
+ };
+
+ var exportListModel = function (options) {
+ assertProperties.assert(options, [
+ 'headers',
+ 'isDailySavedExport',
+ 'isDeid',
+ 'isFeed',
+ 'isOData',
+ 'modelType',
+ 'urls',
+ 'exportOwnershipEnabled'
+ ]);
+
+ var self = {};
+
+ self.modelType = options.modelType;
+ self.isDeid = options.isDeid;
+ self.isDailySavedExport = options.isDailySavedExport;
+ self.isFeed = options.isFeed;
+ self.isOData = options.isOData;
+ self.exportOwnershipEnabled = options.exportOwnershipEnabled;
+
+ assertProperties.assert(options.urls, ['commitFilters', 'getExportsPage', 'poll', 'toggleEnabled', 'update']);
+ self.urls = options.urls;
+
+ assertProperties.assert(options.headers, ['my_export_type', 'shared_export_type', 'export_type_caps_plural']);
+ self.headers = options.headers;
+
+ var panelOptions = _.omit(options, 'headers');
+ self.panels = ko.observableArray([]);
+ if (self.exportOwnershipEnabled) {
+ self.panels.push(exportPanelModel(_.extend({}, panelOptions, {
+ header: self.headers.my_export_type,
+ showOwnership: true,
+ myExports: true,
+ })));
+ self.panels.push(exportPanelModel(_.extend({}, panelOptions, {
+ header: self.headers.shared_export_type,
+ showOwnership: true,
+ myExports: false,
+ })));
+ } else {
+ self.panels.push(exportPanelModel(_.extend({}, panelOptions, {
+ header: self.headers.export_type_caps_plural,
+ showOwnership: false,
+ myExports: false, // value doesn't matter, but knockout will error if there isn't some value
+ })));
+ }
+ self.exports = ko.computed(function () {
+ return _.flatten(_.map(self.panels(), function (p) { return p.exports(); }));
+ });
+
+ self.sendExportAnalytics = function () {
+ kissmetricsAnalytics.track.event("Clicked Export button");
+ return true;
+ };
+
+ // Bulk action handling
+ self.bulkDeleteList = ko.computed(function () {
+ return _.filter(self.exports(), function (e) {return e.addedToBulk();});
+ });
+ self.bulkExportDownloadCount = ko.computed(function () {
+ return self.bulkDeleteList().length;
+ });
+ self.bulkExportList = ko.observable('');
+ self.submitBulkExportDownload = function () {
+ // Update hidden value of exports to download
+ self.bulkExportList(JSON.stringify(_.map(_.filter(self.exports(), function (maybeSelectedExport) {
+ return maybeSelectedExport.addedToBulk();
+ }), function (maybeSelectedExport) {
+ return ko.mapping.toJS(maybeSelectedExport);
+ })));
+
+ return true;
+ };
+
+ var tooltipText = "";
+ if (self.isOData || self.isFeed) {
+ tooltipText = gettext("All of the selected feeds will be deleted.");
+ } else {
+ tooltipText = gettext("All of the selected exports will be deleted.");
+ }
+
+ $(function () {
+ $('[data-toggle="tooltip-bulkExport"]').attr('title',
+ gettext("All of the selected exports will be collected for download to a " +
+ "single Excel file, with each export as a separate sheet.")).tooltip(); /* todo B5: plugin:tooltip */
+ });
+
+ $(function () {
+ $('[data-toggle="tooltip-bulkDelete"]').attr('title', tooltipText).tooltip({trigger: 'hover'}); /* todo B5: plugin:tooltip */
+ });
+
+ self.isMultiple = ko.computed(function () {
+ if (self.bulkDeleteList().length > 1) { return true; }
+ return false;
+ });
+
+ self.BulkExportDelete = function (observable, event) {
+ var count = self.bulkExportDownloadCount;
+ self.panels().forEach(panel => panel.isBulkDeleting(true));
+ var bulkDelete = function () {
+ var selected = _.filter(self.exports(), function (e) { return e.addedToBulk(); });
+ var deleteArray = [];
+ selected.forEach(function (item) {
+ var attr = {};
+ attr["domain"] = item.domain();
+ attr["type"] = item.type();
+ attr["id"] = item.id();
+ if (attr["id"] !== selected[0].id()) {
+ deleteArray.push(attr);
+ }
+ });
+ var deleteList = JSON.stringify(deleteArray);
+ $.ajax({
+ method: 'POST',
+ url: selected[0].deleteUrl(),
+ data: {
+ "count": count,
+ "deleteList": deleteList,
+ },
+ success: function (url) {
+ window.location.href = url;
+ },
+ error: function () {
+ location.reload();
+ },
+ });
+ };
+ if (options.isOData) {
+ kissmetricsAnalytics.track.event("[BI Integration] Deleted Feed");
+ setTimeout(function () {
+ bulkDelete();
+ }, 250);
+ } else {
+ bulkDelete();
+ }
+ };
+
+ // HTML elements from filter form - admittedly it's not very knockout-y to manipulate these directly
+ self.$filterModal = $("#setFeedFiltersModal");
+ self.$emwfCaseFilter = $("#id_emwf_case_filter");
+ self.$emwfFormFilter = $("#id_emwf_form_filter");
+
+ // Data from filter form
+ self.emwfCaseFilter = ko.observableArray().extend({notify: 'always'});
+ self.emwfFormFilter = ko.observableArray().extend({notify: 'always'});
+ self.dateRange = ko.observable().extend({notify: 'always'});
+ self.days = ko.observable().extend({notify: 'always'});
+ self.startDate = ko.observable().extend({
+ notify: 'always',
+ pattern: {
+ message: gettext('Invalid date format'),
+ params: '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$',
+ },
+ });
+ self.endDate = ko.observable().extend({
+ notify: 'always',
+ pattern: {
+ message: gettext('Invalid date format'),
+ params: '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$',
+ },
+ });
+ self.updateLocationRestriction = ko.observable(false);
+
+ // Editing filters for a saved export
+ self.selectedExportModelType = ko.observable();
+ self.filterModalExportId = ko.observable();
+ if (options.isOData) {
+ self.filterModalExportId.subscribe(function (value) {
+ if (value) {
+ kissmetricsAnalytics.track.event("[BI Integration] Clicked Edit Filters button");
+ }
+ });
+ }
+ self.locationRestrictions = ko.observableArray([]).extend({notify: 'always'}); // List of location names. Export will be restricted to these locations.
+ self.formSubmitErrorMessage = ko.observable('');
+ self.dateRegex = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]';
+ self.isSubmittingForm = ko.observable(false);
+
+ self.hasLocationRestrictions = ko.computed(function () {
+ return self.locationRestrictions().length;
+ });
+
+ self.filterModalExportId.subscribe(function (newValue) {
+ if (!newValue) {
+ return;
+ }
+ var newSelectedExport = _.find(self.exports(), function (e) { return e.id() === newValue; });
+ self.$filterModal.find("form")[0].reset();
+ self.selectedExportModelType(newSelectedExport.exportType());
+ self.emwfCaseFilter(newSelectedExport.filters.emwf_case_filter());
+ self.emwfFormFilter(newSelectedExport.filters.emwf_form_filter());
+ self.dateRange(newSelectedExport.filters.date_range());
+ self.days(newSelectedExport.filters.days());
+ self.startDate(newSelectedExport.filters.start_date());
+ self.endDate(newSelectedExport.filters.end_date());
+ if (newSelectedExport.hasEmailedExport) {
+ self.locationRestrictions(newSelectedExport.emailedExport.locationRestrictions());
+ }
+
+ // select2s require programmatic update
+ self._initSelect2Value(self.$emwfCaseFilter, self.emwfCaseFilter());
+ self._initSelect2Value(self.$emwfFormFilter, self.emwfFormFilter());
+ });
+
+ // $el is a select element backing a select2.
+ // value is an array of objects, each with properties 'text' and 'id'
+ self._initSelect2Value = function ($el, value) {
+ $el.empty();
+ _.each(value, function (item) {
+ $el.append(new Option(item.text, item.id));
+ });
+ $el.val(_.pluck(value, 'id'));
+ $el.trigger('change.select2');
+ };
+
+ self.showEmwfCaseFilter = ko.computed(function () {
+ return self.selectedExportModelType() === 'case';
+ });
+ self.showEmwfFormFilter = ko.computed(function () {
+ return self.selectedExportModelType() === 'form';
+ });
+ self.showDays = ko.computed(function () {
+ return self.dateRange() === 'lastn';
+ });
+ self.showStartDate = ko.computed(function () {
+ return self.dateRange() === 'range' || self.dateRange() === 'since';
+ });
+ self.showEndDate = ko.computed(function () {
+ return self.dateRange() === 'range';
+ });
+ self.startDateHasError = ko.computed(function () {
+ return !self.startDate.isValid();
+ });
+ self.endDateHasError = ko.computed(function () {
+ return !self.endDate.isValid();
+ });
+ self.disableSubmit = ko.computed(function () {
+ return self.showStartDate() && self.startDateHasError()
+ || self.showEndDate() && self.endDateHasError();
+ });
+ self.commitFilters = function () {
+ var export_ = _.find(self.exports(), function (e) { return e.id() === self.filterModalExportId(); });
+ self.isSubmittingForm(true);
+
+ var exportType = export_.exportType();
+ if (exportType === 'form') {
+ self.emwfFormFilter(self.$emwfFormFilter.val());
+ self.emwfCaseFilter(null);
+ } else if (exportType === 'case') {
+ self.emwfCaseFilter(self.$emwfCaseFilter.val());
+ self.emwfFormFilter(null);
+ }
+
+ kissmetricsAnalytics.track.event(
+ "[BI Integration] Clicked Save Filters button",
+ {
+ "Date Range": self.dateRange(),
+ }
+ );
+
+ $.ajax({
+ method: 'POST',
+ url: self.urls.commitFilters,
+ data: {
+ export_id: export_.id(),
+ form_data: JSON.stringify({
+ emwf_case_filter: self.emwfCaseFilter(),
+ emwf_form_filter: self.emwfFormFilter(),
+ date_range: self.dateRange(),
+ days: self.days(),
+ start_date: self.startDate(),
+ end_date: self.endDate(),
+ update_location_restriction: self.updateLocationRestriction(),
+ }),
+ is_deid: self.isDeid,
+ is_odata: self.isOData,
+ model_type: self.modelType,
+ },
+ success: function (data) {
+ self.isSubmittingForm(false);
+ if (data.success) {
+ self.formSubmitErrorMessage('');
+ export_.filters.emwf_case_filter(self.emwfCaseFilter());
+ export_.filters.emwf_form_filter(self.emwfFormFilter());
+ export_.filters.date_range(self.dateRange());
+ export_.filters.days(self.days());
+ export_.filters.start_date(self.startDate());
+ export_.filters.end_date(self.endDate());
+ self.locationRestrictions(data.locationRestrictions);
+ if (export_.hasEmailedExport) {
+ export_.emailedExport.pollProgressBar();
+ }
+ self.$filterModal.modal('hide'); /* todo B5: plugin:modal */
+ } else {
+ self.formSubmitErrorMessage(data.error);
+ }
+ },
+ error: function () {
+ self.isSubmittingForm(false);
+ self.formSubmitErrorMessage(gettext("Problem saving dashboard feed filters"));
+ },
+ });
+ };
+
+ return self;
+ };
+
+ return {
+ exportListModel: exportListModel,
+ };
+});
diff --git a/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js b/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js
index 99a0957eae32..a42e6f2a082b 100644
--- a/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js
+++ b/corehq/apps/export/static/export/js/bootstrap5/export_list_main.js
@@ -4,7 +4,7 @@ hqDefine("export/js/bootstrap5/export_list_main", [
'analytix/js/kissmetrix',
'hqwebapp/js/bootstrap5/main',
'export/js/create_export',
- 'export/js/export_list',
+ 'export/js/bootstrap5/export_list',
'hqwebapp/js/select_2_ajax_widget', // for case owner & user filters in DashboardFeedFilterForm
], function (
$,
From ac818fa3473ffb157ff7985714df60862a356263 Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:48:22 +0000
Subject: [PATCH 30/35] "Bootstrap 5 Migration - initial auto-migration for
export/js/download_export.js, splitting templates"
---
.../js/{ => bootstrap3}/download_export.js | 2 +-
.../export/js/bootstrap5/download_export.js | 446 ++++++++++++++++++
.../export/bootstrap3/download_export.html | 2 +-
.../export/bootstrap5/download_export.html | 2 +-
4 files changed, 449 insertions(+), 3 deletions(-)
rename corehq/apps/export/static/export/js/{ => bootstrap3}/download_export.js (99%)
create mode 100644 corehq/apps/export/static/export/js/bootstrap5/download_export.js
diff --git a/corehq/apps/export/static/export/js/download_export.js b/corehq/apps/export/static/export/js/bootstrap3/download_export.js
similarity index 99%
rename from corehq/apps/export/static/export/js/download_export.js
rename to corehq/apps/export/static/export/js/bootstrap3/download_export.js
index 2c9dc3dbc729..3c526304a6b1 100644
--- a/corehq/apps/export/static/export/js/download_export.js
+++ b/corehq/apps/export/static/export/js/bootstrap3/download_export.js
@@ -7,7 +7,7 @@
* downloadProgressModel: Controls the progress bar, etc. once the user has clicked 'Prepare Export'.
* Includes functionality to email the user when the export is done, rather than them waiting for it.
*/
-hqDefine('export/js/download_export', [
+hqDefine('export/js/bootstrap3/download_export', [
'jquery',
'knockout',
'underscore',
diff --git a/corehq/apps/export/static/export/js/bootstrap5/download_export.js b/corehq/apps/export/static/export/js/bootstrap5/download_export.js
new file mode 100644
index 000000000000..15af4310c896
--- /dev/null
+++ b/corehq/apps/export/static/export/js/bootstrap5/download_export.js
@@ -0,0 +1,446 @@
+/**
+ * UI for the page to download an export (form, case, or SMS; single or bulk).
+ *
+ * Contains two models:
+ * downloadFormModel: Controls the form where the user specifies a date range, etc. Also contains
+ * functionality to download the multimedia associated with an export (form exports only).
+ * downloadProgressModel: Controls the progress bar, etc. once the user has clicked 'Prepare Export'.
+ * Includes functionality to email the user when the export is done, rather than them waiting for it.
+ */
+hqDefine('export/js/bootstrap5/download_export', [
+ 'jquery',
+ 'knockout',
+ 'underscore',
+ 'hqwebapp/js/assert_properties',
+ 'hqwebapp/js/initial_page_data',
+ 'analytix/js/google',
+ 'analytix/js/kissmetrix',
+ 'reports/js/filters/bootstrap5/main',
+ 'reports/js/reports.util',
+ 'export/js/utils',
+ 'hqwebapp/js/daterangepicker.config', // createDateRangePicker
+ 'jquery.cookie/jquery.cookie', // for resuming export downloads on refresh
+], function (
+ $,
+ ko,
+ _,
+ assertProperties,
+ initialPageData,
+ googleAnalytics,
+ kissmetricsAnalytics,
+ reportFilters,
+ reportUtils,
+ exportUtils
+) {
+ 'use strict';
+
+ var downloadFormModel = function (options) {
+ assertProperties.assert(options, [
+ 'defaultDateRange',
+ 'exportList',
+ 'exportType',
+ 'formOrCase',
+ 'maxColumnSize',
+ 'multimediaUrl', // present if we should check for multimedia
+ 'progressModel',
+ 'prepareUrl',
+ 'prepareMultimediaUrl',
+ 'smsExport',
+ 'userTypes',
+ ]);
+
+ var self = _.extend({}, options);
+
+ // Form data
+ self.dateRange = ko.observable(self.defaultDateRange);
+ self.getEMW = function () {
+ // "expanded mobile worker" => the users (for forms) or case owners (for cases)
+ return reportUtils.urlSerialize($('form[name="exportFiltersForm"]'));
+ };
+
+ // Cookie Related
+ self.savedDownloadCookieName = _.map(self.exportList, function (exportData) {
+ return exportData.export_id;
+ }).join('.') + '_download';
+ self.savedMultimediaDownloadCookieName = self.savedDownloadCookieName + '_multimedia';
+ self.savedDownloadId = $.cookie(self.savedDownloadCookieName);
+ self.savedMultimediaDownloadId = $.cookie(self.savedMultimediaDownloadCookieName);
+ self.canResumeDownload = !!self.savedDownloadId;
+ self.canResumeMultimediaDownload = !!self.savedMultimediaDownloadId;
+
+ // UI flags
+ self.preparingExport = ko.observable(false);
+ self.prepareExportError = ko.observable('');
+ self.preparingMultimediaExport = ko.observable(false);
+ self.hasMultimedia = ko.observable(false);
+
+ // Once the download starts, this (downloadFormModel) disables the form and displays a message.
+ // When the download is complete, the downloadProgressModel gives the user the option to clear
+ // filters and do another download. Listen for that signal.
+ self.downloadInProgress = ko.observable(self.canResumeDownload || self.canResumeMultimediaDownload);
+
+ // This resumes any refreshed / aborted downloads if cookies are present
+ if (self.canResumeDownload) {
+ self.progressModel.downloadCookieName(self.savedDownloadCookieName);
+ self.progressModel.startDownload(self.savedDownloadId);
+ } else if (self.canResumeMultimediaDownload) {
+ self.progressModel.downloadCookieName(self.savedMultimediaDownloadCookieName);
+ self.progressModel.startMultimediaDownload(self.savedMultimediaDownloadId);
+ }
+
+ self.progressModel.showDownloadStatus.subscribe(function (newValue) {
+ self.downloadInProgress(newValue);
+ });
+
+ self.isValid = ko.computed(function () {
+ return !!self.dateRange();
+ });
+
+ self.disablePrepareExport = ko.computed(function () {
+ return !self.isValid() || self.preparingExport();
+ });
+ self.disablePrepareMultimediaExport = ko.computed(function () {
+ return !self.isValid() || self.preparingMultimediaExport();
+ });
+
+ // Determine whether or not to show button to download multimedia
+ if (self.multimediaUrl) {
+ $.ajax({
+ method: 'GET',
+ url: self.multimediaUrl,
+ data: {
+ export_id: self.exportList[0].export_id,
+ form_or_case: self.formOrCase,
+ },
+ success: function (data) {
+ if (data.success) {
+ self.hasMultimedia(data.hasMultimedia);
+ }
+ },
+ });
+ }
+
+ self.sendAnalytics = function () {
+ var action = (self.exportList.length > 1) ? "Bulk" : "Regular";
+ googleAnalytics.track.event("Download Export", self.exportType, action);
+ _.each(self.exportList, function (export_) {
+ if (export_.has_case_history_table) {
+ googleAnalytics.track.event("Download Case History Export", export_.domain, export_.export_id);
+ }
+ });
+ };
+
+ self.prepareExport = function () {
+ self.prepareExportError('');
+ self.preparingExport(true);
+
+ // Generate human-readable list of mobile workers, to send to analytics
+ function getFilterString() {
+ var filterName = self.exportType === "form" ? "emw" : "case_list_filter",
+ filterNamesAsString = $("form[name='exportFiltersForm']").find("input[name=" + filterName + "]").val(),
+ filterNamesAsArray = filterNamesAsString ? filterNamesAsString.split(',') : [];
+ return _.map(filterNamesAsArray, function (item) {
+ var prefix = "t__";
+ if (item.substring(0, prefix.length) === prefix) {
+ return self.userTypes[item.substring(prefix.length)];
+ }
+ return item;
+ }).join();
+ }
+
+ kissmetricsAnalytics.track.event("Clicked Prepare Export", {
+ "Export type": self.exportType,
+ "filters": getFilterString(),
+ });
+
+ $.ajax({
+ method: 'POST',
+ url: self.prepareUrl,
+ data: {
+ form_or_case: self.formOrCase,
+ sms_export: self.smsExport,
+ exports: JSON.stringify(self.exportList),
+ max_column_size: self.maxColumnSize,
+ form_data: JSON.stringify({
+ date_range: self.dateRange(),
+ emw: self.getEMW(),
+ }),
+ },
+ success: function (data) {
+ if (data.success) {
+ self.sendAnalytics();
+ self.preparingExport(false);
+ self.downloadInProgress(true);
+ self.progressModel.downloadCookieName(self.savedDownloadCookieName);
+ self.progressModel.startDownload(data.download_id);
+ } else {
+ self.handleError(data);
+ }
+ },
+ error: self.handleError,
+ });
+ };
+
+ self.prepareMultimediaExport = function () {
+ self.prepareExportError('');
+ self.preparingMultimediaExport(true);
+ $.ajax({
+ method: 'POST',
+ url: self.prepareMultimediaUrl,
+ data: {
+ form_or_case: self.formOrCase,
+ sms_export: self.smsExport,
+ exports: JSON.stringify(self.exportList),
+ form_data: JSON.stringify({
+ date_range: self.dateRange(),
+ emw: self.getEMW(),
+ }),
+ },
+ success: function (data) {
+ if (data.success) {
+ self.sendAnalytics();
+ self.preparingMultimediaExport(false);
+ self.downloadInProgress(true);
+ self.progressModel.downloadCookieName(self.savedMultimediaDownloadCookieName);
+ self.progressModel.startMultimediaDownload(data.download_id);
+ } else {
+ self.handleError(data);
+ }
+ },
+ error: self.handleError,
+ });
+ };
+
+ self.handleError = function (data) {
+ if (data && data.error) {
+ // The server returned an error message.
+ self.prepareExportError(data.error);
+ } else {
+ self.prepareExportError(gettext("Sorry, there was a problem reaching the server. Please try again."));
+ }
+ self.preparingExport(false);
+ self.preparingMultimediaExport(false);
+ };
+
+ return self;
+ };
+
+ var downloadProgressModel = function (options) {
+ assertProperties.assert(options, ['exportType', 'formOrCase', 'emailUrl', 'pollUrl']);
+
+ var self = {};
+
+ self.exportType = options.exportType;
+ self.formOrCase = options.formOrCase;
+ self.downloadId = ko.observable();
+ self.progress = ko.observable();
+ self.downloadCookieName = ko.observable();
+ self.storeDownloadCookie = function () {
+ if (self.downloadCookieName() && self.downloadId()) {
+ $.cookie(self.downloadCookieName(), self.downloadId(), { path: '/', secure: initialPageData.get('secure_cookies') });
+ }
+ };
+ self.clearDownloadCookie = function () {
+ if (self.downloadCookieName()) {
+ $.removeCookie(self.downloadCookieName(), { path: '/' });
+ }
+ };
+
+ // URLs for user actions
+ self.pollUrl = options.pollUrl;
+ self.emailUrl = options.emailUrl;
+
+ // URLs related to the completed download
+ self.dropboxUrl = ko.observable();
+ self.downloadUrl = ko.observable();
+
+ // UI flags
+ self.showDownloadStatus = ko.observable();
+ self.isDownloaded = ko.observable();
+ self.isDownloadReady = ko.observable();
+ self.isMultimediaDownload = ko.observable();
+ self.sendEmailFlag = ko.observable();
+
+ // Error handling
+ self.progressError = ko.observable();
+ self.celeryError = ko.observable('');
+ self.downloadError = ko.observable('');
+ self.showError = ko.computed(function () {
+ return self.celeryError() || self.downloadError();
+ });
+
+ self.resetDownload = function () {
+ self.downloadId(null);
+ self._numErrors = 0;
+ self._numCeleryRetries = 0;
+ self._lastProgress = 0;
+ self.showDownloadStatus(false);
+ self.isDownloadReady(false);
+ self.isDownloaded(false);
+ self.celeryError('');
+ self.downloadError('');
+ self.isMultimediaDownload(false);
+ self.progress(0);
+ self.progressError('');
+ self.sendEmailFlag(false);
+ self.dropboxUrl('');
+ self.downloadUrl('');
+ };
+ self.resetDownload();
+
+ self.startDownload = function (downloadId) {
+ self.showDownloadStatus(true);
+ self.downloadId(downloadId);
+ self.storeDownloadCookie();
+ self.interval = setInterval(self._checkDownloadProgress, 2000);
+ };
+
+ self.startMultimediaDownload = function (downloadId) {
+ self.isMultimediaDownload(true);
+ self.startDownload(downloadId);
+ };
+
+ self.clickDownload = function () {
+ self.isDownloaded(true);
+ self.sendAnalytics();
+ self.clearDownloadCookie();
+ return true; // allow default click action
+ };
+
+ self.sendAnalytics = function () {
+ googleAnalytics.track.event("Download Export", exportUtils.capitalize(self.exportType), "Saved");
+ kissmetricsAnalytics.track.event("Clicked Download button");
+ };
+
+ self._checkDownloadProgress = function () {
+ $.ajax({
+ method: 'GET',
+ url: self.pollUrl,
+ data: {
+ form_or_case: self.formOrCase,
+ download_id: self.downloadId,
+ },
+ success: function (data) {
+ if (data.is_poll_successful) {
+ self._updateProgressBar(data);
+ self.downloadId(data.download_id);
+ if (data.has_file && data.is_ready) {
+ clearInterval(self.interval);
+ return;
+ }
+ if (data.progress && data.progress.error) {
+ clearInterval(self.interval);
+ self.progressError(data.progress.error_message);
+ self.clearDownloadCookie();
+ return;
+ }
+ if (data.progress.current > self._lastProgress) {
+ self._lastProgress = data.progress.current;
+ // processing is still going, keep moving.
+ // this avoids failing hard prematurely at celery errors if
+ // the polling is still reporting forward progress.
+ self._numCeleryRetries = 0;
+ return;
+ }
+ }
+ if (data.error) {
+ self._dealWithErrors(data);
+ }
+ if (_.isNull(data.is_alive)) {
+ self._dealWithCeleryErrors();
+ }
+ },
+ error: self._dealWithErrors,
+ });
+ };
+
+ self._dealWithCeleryErrors = function () {
+ // Sometimes the task handler for celery is a little slow to get
+ // started, so we have to try a few times.
+ if (self._numCeleryRetries > 10) {
+ clearInterval(self.interval);
+ self.clearDownloadCookie();
+ self.celeryError(gettext("Server maintenance in progress. Please try again later."));
+ }
+ self._numCeleryRetries ++;
+ };
+
+ self._dealWithErrors = function (data) {
+ if (self._numErrors > 3) {
+ if (data && data.error) {
+ self.downloadError(data.error);
+ } else {
+ self.downloadError(gettext("There was an error downloading your export."));
+ }
+ clearInterval(self.interval);
+ self.clearDownloadCookie();
+ }
+ self._numErrors ++;
+ };
+
+ self._updateProgressBar = function (data) {
+ var progressPercent = 0;
+ if (data.is_ready && data.has_file) {
+ progressPercent = 100;
+ self.isDownloadReady(true);
+ self.dropboxUrl(data.dropbox_url);
+ self.downloadUrl(data.download_url);
+ } else if (_.isNumber(data.progress.percent)) {
+ progressPercent = data.progress.percent;
+ }
+ self.progress(progressPercent);
+ };
+
+ self.sendEmailUponCompletion = function () {
+ self.sendEmailFlag(true);
+ $.ajax({
+ method: 'POST',
+ dataType: 'json',
+ url: self.emailUrl,
+ data: { download_id: self.downloadId },
+ });
+ };
+
+ return self;
+ };
+
+ $(function () {
+ reportFilters.init();
+
+ var exportList = initialPageData.get('export_list'),
+ exportType = exportList[0].export_type;
+
+ var progressModel = downloadProgressModel({
+ exportType: exportType,
+ emailUrl: initialPageData.reverse('add_export_email_request'),
+ formOrCase: initialPageData.get('form_or_case'),
+ pollUrl: initialPageData.reverse('poll_custom_export_download'),
+ });
+
+ $("#download-export-form").koApplyBindings(downloadFormModel({
+ defaultDateRange: initialPageData.get('default_date_range'),
+ exportList: exportList,
+ exportType: exportType,
+ formOrCase: initialPageData.get('form_or_case'),
+ maxColumnSize: initialPageData.get('max_column_size') || 2000,
+ multimediaUrl: initialPageData.get('check_for_multimedia') ? initialPageData.reverse('has_multimedia') : '',
+ progressModel: progressModel,
+ prepareUrl: initialPageData.reverse('prepare_custom_export'),
+ prepareMultimediaUrl: initialPageData.reverse('prepare_form_multimedia'),
+ smsExport: initialPageData.get('sms_export'),
+ userTypes: initialPageData.get('user_types'),
+ }));
+
+ $("#download-progress").koApplyBindings(progressModel);
+
+ $(".hqwebapp-datespan").each(function () {
+ var $el = $(this).find("input");
+ $el.createDateRangePicker( /* todo B5: plugin:createDateRangePicker */
+ $el.data("labels"),
+ $el.data("separator"),
+ $el.data('startDate'),
+ $el.data('endDate')
+ );
+ });
+ });
+});
diff --git a/corehq/apps/export/templates/export/bootstrap3/download_export.html b/corehq/apps/export/templates/export/bootstrap3/download_export.html
index e8d7bf7641a5..7ae464c95efa 100644
--- a/corehq/apps/export/templates/export/bootstrap3/download_export.html
+++ b/corehq/apps/export/templates/export/bootstrap3/download_export.html
@@ -34,7 +34,7 @@
{% endblock stylesheets %}
-{% requirejs_main 'export/js/download_export' %}
+{% requirejs_main 'export/js/bootstrap3/download_export' %}
{% block page_title %}
{{ current_page.title }}
diff --git a/corehq/apps/export/templates/export/bootstrap5/download_export.html b/corehq/apps/export/templates/export/bootstrap5/download_export.html
index 4b3d1211ac82..ce80ca7417a2 100644
--- a/corehq/apps/export/templates/export/bootstrap5/download_export.html
+++ b/corehq/apps/export/templates/export/bootstrap5/download_export.html
@@ -34,7 +34,7 @@
{% endblock stylesheets %}
-{% requirejs_main_b5 'export/js/download_export' %}
+{% requirejs_main_b5 'export/js/bootstrap5/download_export' %}
{% block page_title %}
{{ current_page.title }}
From 4f881be2d4cf90fbecebe07869a1c36ea760887e Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:57:05 +0000
Subject: [PATCH 31/35] "Bootstrap 5 Migration - initial auto-migration for
export/spec/ko/mocha.html, splitting templates"
---
.../export/spec/ko/{ => bootstrap3}/mocha.html | 0
.../export/spec/ko/bootstrap5/mocha.html | 15 +++++++++++++++
2 files changed, 15 insertions(+)
rename corehq/apps/export/templates/export/spec/ko/{ => bootstrap3}/mocha.html (100%)
create mode 100644 corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html
diff --git a/corehq/apps/export/templates/export/spec/ko/mocha.html b/corehq/apps/export/templates/export/spec/ko/bootstrap3/mocha.html
similarity index 100%
rename from corehq/apps/export/templates/export/spec/ko/mocha.html
rename to corehq/apps/export/templates/export/spec/ko/bootstrap3/mocha.html
diff --git a/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html b/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html
new file mode 100644
index 000000000000..caf3c8832eca
--- /dev/null
+++ b/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html
@@ -0,0 +1,15 @@
+{% extends 'mocha/base.html' %}
+{% load hq_shared_tags %}
+
+{% block dependencies %}
+
+
+
+{% endblock %}
+
+{% block mocha_tests %}
+
+
+
+
+{% endblock %}
From c862394ed59223f82c4989b29d686696fb7da16e Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 16:57:39 +0000
Subject: [PATCH 32/35] "Bootstrap 5 Migration - initial auto-migration for
export/spec/ExportColumn.spec.js, splitting templates"
---
.../{ => bootstrap3}/ExportColumn.spec.js | 2 +-
.../spec/bootstrap5/ExportColumn.spec.js | 87 +++++++++++++++++++
.../export/spec/ko/bootstrap3/mocha.html | 2 +-
.../export/spec/ko/bootstrap5/mocha.html | 2 +-
4 files changed, 90 insertions(+), 3 deletions(-)
rename corehq/apps/export/static/export/spec/{ => bootstrap3}/ExportColumn.spec.js (97%)
create mode 100644 corehq/apps/export/static/export/spec/bootstrap5/ExportColumn.spec.js
diff --git a/corehq/apps/export/static/export/spec/ExportColumn.spec.js b/corehq/apps/export/static/export/spec/bootstrap3/ExportColumn.spec.js
similarity index 97%
rename from corehq/apps/export/static/export/spec/ExportColumn.spec.js
rename to corehq/apps/export/static/export/spec/bootstrap3/ExportColumn.spec.js
index b1386e035ec6..396a33d64017 100644
--- a/corehq/apps/export/static/export/spec/ExportColumn.spec.js
+++ b/corehq/apps/export/static/export/spec/bootstrap3/ExportColumn.spec.js
@@ -1,5 +1,5 @@
/* eslint-env mocha */
-hqDefine("export/spec/ExportColumn.spec", [
+hqDefine("export/spec/bootstrap3/ExportColumn.spec", [
'underscore',
'export/js/bootstrap3/models',
], function (
diff --git a/corehq/apps/export/static/export/spec/bootstrap5/ExportColumn.spec.js b/corehq/apps/export/static/export/spec/bootstrap5/ExportColumn.spec.js
new file mode 100644
index 000000000000..8f740a1bd09e
--- /dev/null
+++ b/corehq/apps/export/static/export/spec/bootstrap5/ExportColumn.spec.js
@@ -0,0 +1,87 @@
+/* eslint-env mocha */
+hqDefine("export/spec/bootstrap5/ExportColumn.spec", [
+ 'underscore',
+ 'export/js/bootstrap5/models',
+], function (
+ _,
+ viewModels
+) {
+ describe('ExportColumn', function () {
+ var selectedColumn,
+ advancedColumn,
+ deletedColumn,
+ table,
+ instance;
+
+ beforeEach(function () {
+ var mockObservable = function () { return 'foo'; };
+
+ selectedColumn = {
+ selected: true,
+ is_advanced: true,
+ is_deleted: true,
+ deid_transform: null,
+ item: { label: mockObservable },
+ label: mockObservable,
+ tags: [],
+ };
+ advancedColumn = {
+ selected: false,
+ is_advanced: true,
+ is_deleted: false,
+ deid_transform: null,
+ item: { label: mockObservable },
+ label: mockObservable,
+ tags: [],
+ };
+ deletedColumn = {
+ selected: false,
+ is_advanced: false,
+ is_deleted: true,
+ deid_transform: null,
+ item: { label: mockObservable },
+ label: mockObservable,
+ tags: [],
+ };
+ table = {
+ name: 'table',
+ selected: true,
+ columns: [
+ selectedColumn,
+ advancedColumn,
+ deletedColumn,
+ ],
+ };
+ instance = new viewModels.ExportInstance({
+ name: 'instance',
+ is_deidentified: false,
+ export_format: 'csv',
+ tables: [table],
+ });
+ });
+
+ it('should properly show visible columns', function () {
+ var columns,
+ table = instance.tables()[0];
+
+
+ columns = _.filter(table.columns(), function (c) { return c.isVisible(table); });
+
+ // Only the selected one should be visible
+ assert.equal(columns.length, 1);
+ assert.isTrue(columns[0].selected());
+
+ table.toggleShowAdvanced(table);
+ columns = _.filter(table.columns(), function (c) { return c.isVisible(table); });
+
+ // Only the selected one and the advanced one should be visible
+ assert.equal(columns.length, 2);
+
+ instance.toggleShowDeleted(table);
+ columns = _.filter(table.columns(), function (c) { return c.isVisible(table); });
+
+ // All the columns should be visible
+ assert.equal(columns.length, 3);
+ });
+ });
+});
diff --git a/corehq/apps/export/templates/export/spec/ko/bootstrap3/mocha.html b/corehq/apps/export/templates/export/spec/ko/bootstrap3/mocha.html
index 75aca65e9973..406969bc8dbc 100644
--- a/corehq/apps/export/templates/export/spec/ko/bootstrap3/mocha.html
+++ b/corehq/apps/export/templates/export/spec/ko/bootstrap3/mocha.html
@@ -10,6 +10,6 @@
{% block mocha_tests %}
-
+
{% endblock %}
diff --git a/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html b/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html
index caf3c8832eca..5a05ff8ead0b 100644
--- a/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html
+++ b/corehq/apps/export/templates/export/spec/ko/bootstrap5/mocha.html
@@ -10,6 +10,6 @@
{% block mocha_tests %}
-
+
{% endblock %}
From 9ec9533098457ac7839d26a4dfb69ee407d8c89a Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 17:01:04 +0000
Subject: [PATCH 33/35] "Bootstrap 5 Migration - Updated 'Gruntfile.js' after
splitting 'export'."
---
Gruntfile.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Gruntfile.js b/Gruntfile.js
index 14578f4dc97e..a01f98451e71 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -28,7 +28,8 @@ module.exports = function (grunt) {
*/
var apps = [
'app_manager',
- 'export/ko',
+ 'export/ko/bootstrap3',
+ 'export/ko/bootstrap5',
'notifications/bootstrap3',
'notifications/bootstrap5',
'reports_core/choiceListUtils',
From b72dd620ce6262e2e888f3f9c5c110221f5cc58a Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 17:03:10 +0000
Subject: [PATCH 34/35] "Bootstrap 5 Migration - Updated diff config for
'export'"
---
.../tests/data/bootstrap5_diff_config.json | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diff_config.json b/corehq/apps/hqwebapp/tests/data/bootstrap5_diff_config.json
index 75a5f82ef875..56022acfe999 100644
--- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diff_config.json
+++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diff_config.json
@@ -664,5 +664,65 @@
"label": "javascript/repeaters/js",
"compare_all_files": true
}
+ ],
+ "apps/export/templates/export": [
+ {
+ "directories": [
+ "bootstrap3",
+ "bootstrap5"
+ ],
+ "file_type": "template",
+ "label": "export",
+ "compare_all_files": true
+ },
+ {
+ "directories": [
+ "dialogs/bootstrap3",
+ "dialogs/bootstrap5"
+ ],
+ "file_type": "template",
+ "label": "export/dialogs",
+ "compare_all_files": true
+ },
+ {
+ "directories": [
+ "partials/bootstrap3",
+ "partials/bootstrap5"
+ ],
+ "file_type": "template",
+ "label": "export/partials",
+ "compare_all_files": true
+ },
+ {
+ "directories": [
+ "spec/ko/bootstrap3",
+ "spec/ko/bootstrap5"
+ ],
+ "file_type": "template",
+ "label": "export/spec/ko",
+ "compare_all_files": true
+ }
+ ],
+ "apps/export/static/export/js": [
+ {
+ "directories": [
+ "bootstrap3",
+ "bootstrap5"
+ ],
+ "file_type": "javascript",
+ "label": "javascript/export/js",
+ "compare_all_files": true
+ }
+ ],
+ "apps/export/static/export/spec": [
+ {
+ "directories": [
+ "bootstrap3",
+ "bootstrap5"
+ ],
+ "file_type": "javascript",
+ "label": "javascript/export/spec",
+ "compare_all_files": true
+ }
]
}
From b43d3a8a7c698cccdb6ba8a74a1e47688b92ccbd Mon Sep 17 00:00:00 2001
From: Jenny Schweers
Date: Wed, 11 Sep 2024 17:05:24 +0000
Subject: [PATCH 35/35] "Bootstrap 5 Migration - Rebuilt diffs"
---
.../export/customize_export_new.html.diff.txt | 287 ++++++++++++
.../datasource_export_view.html.diff.txt | 19 +
..._delete_custom_export_dialog.html.diff.txt | 40 ++
.../delete_custom_export_dialog.html.diff.txt | 28 ++
.../process_deleted_questions.html.diff.txt | 31 ++
...rocess_deprecated_properties.html.diff.txt | 22 +
.../export/download_data_files.html.diff.txt | 92 ++++
.../export/download_export.html.diff.txt | 29 ++
.../export/export_list.html.diff.txt | 24 ++
.../partials/delete_bulk_notice.html.diff.txt | 26 ++
.../partials/export_bulk_notice.html.diff.txt | 22 +
.../export_download_prepare.html.diff.txt | 50 +++
.../export_download_progress.html.diff.txt | 89 ++++
.../export_list_controller.html.diff.txt | 58 +++
...ort_list_create_export_modal.html.diff.txt | 55 +++
.../partials/feed_filter_modal.html.diff.txt | 38 ++
...w_customize_export_templates.html.diff.txt | 301 +++++++++++++
...ata_feed_limit_reached_modal.html.diff.txt | 22 +
.../export/partials/table.html.diff.txt | 407 ++++++++++++++++++
.../export/paywall.html.diff.txt | 37 ++
.../export/spec/ko/mocha.html.diff.txt | 19 +
.../js/customize_export_new.js.diff.txt | 22 +
.../export/js/download_data_files.js.diff.txt | 11 +
.../export/js/download_export.js.diff.txt | 29 ++
.../export/js/export_list.js.diff.txt | 63 +++
.../export/js/export_list_main.js.diff.txt | 16 +
.../export/js/incremental_export.js.diff.txt | 12 +
.../javascript/export/js/models.js.diff.txt | 40 ++
.../export/spec/ExportColumn.spec.js.diff.txt | 12 +
.../spec/ExportInstance.spec.js.diff.txt | 15 +
.../spec/Exports.Utils.spec.js.diff.txt | 13 +
31 files changed, 1929 insertions(+)
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/customize_export_new.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/datasource_export_view.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/dialogs/bulk_delete_custom_export_dialog.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/dialogs/delete_custom_export_dialog.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/dialogs/process_deleted_questions.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/dialogs/process_deprecated_properties.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/download_data_files.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/download_export.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/export_list.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/delete_bulk_notice.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/export_bulk_notice.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/export_download_prepare.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/export_download_progress.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/export_list_controller.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/export_list_create_export_modal.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/feed_filter_modal.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/new_customize_export_templates.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/odata_feed_limit_reached_modal.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/partials/table.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/paywall.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/spec/ko/mocha.html.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/customize_export_new.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/download_data_files.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/download_export.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/export_list.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/export_list_main.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/incremental_export.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/js/models.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/spec/ExportColumn.spec.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/spec/ExportInstance.spec.js.diff.txt
create mode 100644 corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/export/spec/Exports.Utils.spec.js.diff.txt
diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/customize_export_new.html.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/customize_export_new.html.diff.txt
new file mode 100644
index 000000000000..92643cc96984
--- /dev/null
+++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/export/customize_export_new.html.diff.txt
@@ -0,0 +1,287 @@
+---
++++
+@@ -1,8 +1,8 @@
+-{% extends "hqwebapp/bootstrap3/base_section.html" %}
++{% extends "hqwebapp/bootstrap5/base_section.html" %}
+ {% load hq_shared_tags %}
+ {% load i18n %}
+
+-{% requirejs_main 'export/js/bootstrap3/customize_export_new' %}
++{% requirejs_main_b5 'export/js/bootstrap5/customize_export_new' %}
+
+ {% block page_content %}
+ {% initial_page_data 'number_of_apps_to_process' number_of_apps_to_process %}
+@@ -15,10 +15,10 @@
+ {% initial_page_data 'export_instance' export_instance %}
+ {% initial_page_data 'geo_properties' geo_properties %}
+
+-
++
{# todo B5: inline style #}
+ {# content for multi-select help popover #}
+ {% if export_instance.type == 'case' %}
+-
++
{# todo B5: inline style #}
+ {% blocktrans %}
+ These options allow you to configure how CommCare exports data from multi-select questions.
+ If you do not want to split the options into multiple columns select the 'plain' option.
+@@ -40,16 +40,16 @@
+ method="post">
+ {% csrf_token %}
+
+-