diff --git a/corehq/apps/app_manager/helpers/validators.py b/corehq/apps/app_manager/helpers/validators.py
index 8f17aedb3f1d..38570a1b4c34 100644
--- a/corehq/apps/app_manager/helpers/validators.py
+++ b/corehq/apps/app_manager/helpers/validators.py
@@ -545,6 +545,11 @@ def validate_search_config(self):
"module": self.get_module_info(),
"property": prop.name,
}
+ if search_config.search_on_clear and self.module.is_auto_select():
+ yield {
+ "type": "search on clear with auto select",
+ "module": self.get_module_info(),
+ }
def validate_case_list_field_actions(self):
if hasattr(self.module, 'case_details'):
diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py
index dbfd3f0540ed..4d0f4239ad60 100644
--- a/corehq/apps/app_manager/models.py
+++ b/corehq/apps/app_manager/models.py
@@ -2188,6 +2188,7 @@ class CaseSearch(DocumentSchema):
description = LabelProperty(default={})
include_all_related_cases = BooleanProperty(default=False)
dynamic_search = BooleanProperty(default=False)
+ search_on_clear = BooleanProperty(default=False)
# case property referencing another case's ID
custom_related_case_property = StringProperty(exclude_if_none=True)
diff --git a/corehq/apps/app_manager/static/app_manager/js/details/case_claim.js b/corehq/apps/app_manager/static/app_manager/js/details/case_claim.js
index 66f525e0b762..6d30544c7124 100644
--- a/corehq/apps/app_manager/static/app_manager/js/details/case_claim.js
+++ b/corehq/apps/app_manager/static/app_manager/js/details/case_claim.js
@@ -203,6 +203,7 @@ hqDefine("app_manager/js/details/case_claim", function () {
'title_label', 'description', 'search_button_display_condition', 'search_label', 'search_filter',
'additional_relevant', 'data_registry', 'data_registry_workflow', 'additional_registry_cases',
'custom_related_case_property', 'inline_search', 'instance_name', 'include_all_related_cases',
+ 'search_on_clear',
];
var searchConfigModel = function (options, lang, searchFilterObservable, saveButton) {
hqImport("hqwebapp/js/assert_properties").assertRequired(options, searchConfigKeys);
diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py
index da8034ea6683..1c200f827b58 100644
--- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py
+++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py
@@ -207,19 +207,23 @@ def build_session(self):
)
def build_remote_request_queries(self):
+ kwargs = {
+ "url": absolute_reverse('app_aware_remote_search', args=[self.app.domain, self.app._id]),
+ "storage_instance": self.storage_instance,
+ "template": 'case',
+ "title": self.build_title() if self.app.enable_case_search_title_translation else None,
+ "description": self.build_description() if self.module.search_config.description != {} else None,
+ "data": self._remote_request_query_datums,
+ "prompts": self.build_query_prompts(),
+ "prompt_groups": self.build_query_prompt_groups(),
+ "default_search": self.module.search_config.default_search,
+ "dynamic_search": self.app.split_screen_dynamic_search and not self.module.is_auto_select()
+ }
+ if self.module.search_config.search_on_clear and toggles.SPLIT_SCREEN_CASE_SEARCH.enabled(self.app.domain):
+ kwargs["search_on_clear"] = (self.module.search_config.search_on_clear
+ and not self.module.is_auto_select())
return [
- RemoteRequestQuery(
- url=absolute_reverse('app_aware_remote_search', args=[self.app.domain, self.app._id]),
- storage_instance=self.storage_instance,
- template='case',
- title=self.build_title() if self.app.enable_case_search_title_translation else None,
- description=self.build_description() if self.module.search_config.description != {} else None,
- data=self._remote_request_query_datums,
- prompts=self.build_query_prompts(),
- prompt_groups=self.build_query_prompt_groups(),
- default_search=self.module.search_config.default_search,
- dynamic_search=self.app.split_screen_dynamic_search and not self.module.is_auto_select(),
- )
+ RemoteRequestQuery(**kwargs)
]
def build_remote_request_datums(self):
diff --git a/corehq/apps/app_manager/suite_xml/xml_models.py b/corehq/apps/app_manager/suite_xml/xml_models.py
index 0dfe6a511df1..8576a0e73470 100644
--- a/corehq/apps/app_manager/suite_xml/xml_models.py
+++ b/corehq/apps/app_manager/suite_xml/xml_models.py
@@ -593,6 +593,7 @@ class RemoteRequestQuery(OrderedXmlObject, XmlObject):
prompt_groups = NodeListField('group', QueryPromptGroup)
default_search = BooleanField("@default_search")
dynamic_search = BooleanField("@dynamic_search")
+ search_on_clear = BooleanField("@search_on_clear", required=False)
@property
def id(self):
diff --git a/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html b/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html
index b91d248628c9..617ac182ba41 100644
--- a/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html
+++ b/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html
@@ -195,6 +195,11 @@
{% blocktrans with module_name=error.module.name|trans:langs %}
The case list in {{ module_name }} can not use the same "search input instance name" as its Parent Select Menu.
{% endblocktrans %}
+ {% case "search on clear with auto select" %}
+ {% blocktrans with module_name=error.module.name|trans:langs %}
+ The case list in {{ module_name }} uses both multi-select auto select and "Clearing search terms resets search results".
+ These two features are not compatible.
+ {% endblocktrans %}
{% case "inline search to display only forms" %}
{% blocktrans with module_name=error.module.name|trans:langs %}
{{ module_name }}
diff --git a/corehq/apps/app_manager/templates/app_manager/partials/modules/case_search_properties.html b/corehq/apps/app_manager/templates/app_manager/partials/modules/case_search_properties.html
index 9bc44dbbe15b..3af572b67f55 100644
--- a/corehq/apps/app_manager/templates/app_manager/partials/modules/case_search_properties.html
+++ b/corehq/apps/app_manager/templates/app_manager/partials/modules/case_search_properties.html
@@ -466,11 +466,23 @@ {% trans "Search and Claim Options" %
{% endif %}
+ {% if request|toggle_enabled:'SPLIT_SCREEN_CASE_SEARCH' and not app.split_screen_dynamic_search%}
+
+ {% endif %}
{% blocktrans %}
This is not a valid xpath expression. Check to make sure your parentheses match and you are referencing case properties correctly.
{% endblocktrans %}
-
+
diff --git a/corehq/apps/app_manager/tests/test_build_errors.py b/corehq/apps/app_manager/tests/test_build_errors.py
index 223937095594..b41adcb8789d 100644
--- a/corehq/apps/app_manager/tests/test_build_errors.py
+++ b/corehq/apps/app_manager/tests/test_build_errors.py
@@ -418,3 +418,16 @@ def test_form_link_validation_mismatched_shadow_module(self, *args):
'module': {'id': 0, 'name': {'en': 'm0 module'}},
'form': {'id': 0, 'name': {'en': 'm0 form 0'}},
}, errors)
+
+ @patch('corehq.apps.app_manager.models.ModuleBase.is_auto_select', return_value=True)
+ def test_search_on_clear_with_auto_select(self, *args):
+ factory = AppFactory()
+ module = factory.new_basic_module('basic', 'person', with_form=False)
+ module.search_config = CaseSearch(
+ search_on_clear=True,
+ )
+ errors = factory.app.validate_app()
+ self.assertIn({
+ 'type': 'search on clear with auto select',
+ 'module': {'id': 0, 'unique_id': 'basic_module', 'name': {'en': 'basic module'}},
+ }, errors)
diff --git a/corehq/apps/app_manager/tests/test_suite_split_screen_case_search.py b/corehq/apps/app_manager/tests/test_suite_split_screen_case_search.py
index 7aa856fd13e2..5e68a30a06ff 100644
--- a/corehq/apps/app_manager/tests/test_suite_split_screen_case_search.py
+++ b/corehq/apps/app_manager/tests/test_suite_split_screen_case_search.py
@@ -56,8 +56,10 @@ def setUp(self):
self.module.search_config = CaseSearch(
properties=[
CaseSearchProperty(name='name', label={'en': 'Name'}),
- ]
+ ],
+ search_on_clear=True,
)
+
self.module.assign_references()
# wrap to have assign_references called
self.app = Application.wrap(self.app.to_json())
@@ -78,3 +80,17 @@ def test_dynamic_search_suite_disable_with_auto_select(self, mock):
suite = parse_normalize(suite, to_string=False)
self.assertEqual(True, self.module.is_auto_select())
self.assertEqual("false", suite.xpath("./remote-request[1]/session/query/@dynamic_search")[0])
+
+ @flag_enabled('SPLIT_SCREEN_CASE_SEARCH')
+ def test_search_on_clear(self):
+ suite = self.app.create_suite()
+ suite = parse_normalize(suite, to_string=False)
+ self.assertEqual("true", suite.xpath("./remote-request[1]/session/query/@search_on_clear")[0])
+
+ @patch('corehq.apps.app_manager.models.ModuleBase.is_auto_select', return_value=True)
+ @flag_enabled('SPLIT_SCREEN_CASE_SEARCH')
+ def test_search_on_clear_disable_with_auto_select(self, mock):
+ suite = self.app.create_suite()
+ suite = parse_normalize(suite, to_string=False)
+ self.assertEqual(True, self.module.is_auto_select())
+ self.assertEqual("false", suite.xpath("./remote-request[1]/session/query/@search_on_clear")[0])
diff --git a/corehq/apps/app_manager/views/modules.py b/corehq/apps/app_manager/views/modules.py
index 5c8aa2f5f365..40f5e69ac84f 100644
--- a/corehq/apps/app_manager/views/modules.py
+++ b/corehq/apps/app_manager/views/modules.py
@@ -282,6 +282,7 @@ def _get_shared_module_view_context(request, app, module, case_property_builder,
'instance_name': module.search_config.instance_name or "",
'include_all_related_cases': module.search_config.include_all_related_cases,
'dynamic_search': app.split_screen_dynamic_search,
+ 'search_on_clear': module.search_config.search_on_clear,
},
},
}
@@ -1395,6 +1396,7 @@ def _check_xpath(xpath, location):
instance_name=instance_name,
include_all_related_cases=search_properties.get('include_all_related_cases', False),
dynamic_search=app.split_screen_dynamic_search and not module.is_auto_select(),
+ search_on_clear=search_properties.get('search_on_clear', False),
)
diff --git a/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/collections.js b/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/collections.js
index 20990d11ecfc..fb9289643027 100644
--- a/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/collections.js
+++ b/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/collections.js
@@ -75,6 +75,7 @@ hqDefine("cloudcare/js/formplayer/menus/collections", function () {
queryProperties: [
'groupHeaders',
+ 'searchOnClear',
],
parse: function (response) {
diff --git a/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/controller.js b/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/controller.js
index 4d9711e68688..a0a4b58bdbb1 100644
--- a/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/controller.js
+++ b/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/controller.js
@@ -106,26 +106,44 @@ hqDefine("cloudcare/js/formplayer/menus/controller", function () {
var showMenu = function (menuResponse) {
var menuListView = menusUtils.getMenuView(menuResponse);
var appPreview = FormplayerFrontend.currentUser.displayOptions.singleAppMode;
- var queryResponse = menuResponse.queryResponse;
var sidebarEnabled = !appPreview && menusUtils.isSidebarEnabled(menuResponse);
- if (sidebarEnabled && menuResponse.type === constants.QUERY) {
- var menuData = menusUtils.getMenuData(menuResponse);
- menuData["triggerEmptyCaseList"] = true;
- menuData["sidebarEnabled"] = true;
- menuData["description"] = menuResponse.description;
-
- var caseListView = menusUtils.getCaseListView(menuResponse);
- FormplayerFrontend.regions.getRegion('main').show(caseListView(menuData));
- } else if (menuListView) {
+ if (menuListView && !sidebarEnabled) {
FormplayerFrontend.regions.getRegion('main').show(menuListView);
}
+ if (sidebarEnabled) {
+ showSplitScreenQuery(menuResponse, menuListView);
+ } else {
+ FormplayerFrontend.regions.getRegion('sidebar').empty();
+ }
if (menuResponse.persistentCaseTile && !appPreview) {
showPersistentCaseTile(menuResponse.persistentCaseTile);
} else {
FormplayerFrontend.regions.getRegion('persistentCaseTile').empty();
}
- if (sidebarEnabled && menuResponse.type === constants.ENTITIES && queryResponse) {
+ if (menuResponse.breadcrumbs) {
+ menusUtils.showBreadcrumbs(menuResponse.breadcrumbs);
+ if (!appPreview) {
+ let isFormEntry = !menuResponse.queryKey;
+ if (isFormEntry) {
+ menusUtils.showMenuDropdown(menuResponse.langs, initialPageData.get('lang_code_name_mapping'));
+ }
+ if (menuResponse.type === constants.ENTITIES) {
+ menusUtils.showMenuDropdown();
+ }
+ }
+ } else {
+ FormplayerFrontend.regions.getRegion('breadcrumb').empty();
+ }
+ if (menuResponse.appVersion) {
+ FormplayerFrontend.trigger('setVersionInfo', menuResponse.appVersion);
+ }
+ };
+
+ var showSplitScreenQuery = function (menuResponse, menuListView) {
+ var menuData = menusUtils.getMenuData(menuResponse);
+ var queryResponse = menuResponse.queryResponse;
+ if (menuResponse.type === constants.ENTITIES && queryResponse) {
var queryCollection = new Collection(queryResponse.displays);
FormplayerFrontend.regions.getRegion('sidebar').show(
queryView.queryListView({
@@ -136,9 +154,11 @@ hqDefine("cloudcare/js/formplayer/menus/controller", function () {
sidebarEnabled: true,
disableDynamicSearch: !sessionStorage.submitPerformed,
groupHeaders: queryResponse.groupHeaders,
+ searchOnClear: queryResponse.searchOnClear,
}).render()
);
- } else if (sidebarEnabled && menuResponse.type === constants.QUERY) {
+ FormplayerFrontend.regions.getRegion('main').show(menuListView);
+ } else if (menuResponse.type === constants.QUERY) {
FormplayerFrontend.regions.getRegion('sidebar').show(
queryView.queryListView({
collection: menuResponse,
@@ -148,28 +168,16 @@ hqDefine("cloudcare/js/formplayer/menus/controller", function () {
sidebarEnabled: true,
disableDynamicSearch: true,
groupHeaders: menuResponse.groupHeaders,
+ searchOnClear: menuResponse.searchOnClear,
}).render()
);
- } else {
- FormplayerFrontend.regions.getRegion('sidebar').empty();
- }
- if (menuResponse.breadcrumbs) {
- menusUtils.showBreadcrumbs(menuResponse.breadcrumbs);
- if (!appPreview) {
- let isFormEntry = !menuResponse.queryKey;
- if (isFormEntry) {
- menusUtils.showMenuDropdown(menuResponse.langs, initialPageData.get('lang_code_name_mapping'));
- }
- if (menuResponse.type === constants.ENTITIES) {
- menusUtils.showMenuDropdown();
- }
- }
- } else {
- FormplayerFrontend.regions.getRegion('breadcrumb').empty();
- }
- if (menuResponse.appVersion) {
- FormplayerFrontend.trigger('setVersionInfo', menuResponse.appVersion);
+ menuData["triggerEmptyCaseList"] = true;
+ menuData["sidebarEnabled"] = true;
+ menuData["description"] = menuResponse.description;
+
+ var caseListView = menusUtils.getCaseListView(menuResponse);
+ FormplayerFrontend.regions.getRegion('main').show(caseListView(menuData));
}
};
diff --git a/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/views/query.js b/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/views/query.js
index c83de350b53e..7d57f889ddc5 100644
--- a/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/views/query.js
+++ b/corehq/apps/cloudcare/static/cloudcare/js/formplayer/menus/views/query.js
@@ -586,6 +586,7 @@ hqDefine("cloudcare/js/formplayer/menus/views/query", function () {
this.dynamicSearchEnabled = !(options.disableDynamicSearch || this.smallScreenEnabled) &&
(toggles.toggleEnabled('DYNAMICALLY_UPDATE_SEARCH_RESULTS') && this.options.sidebarEnabled);
+ this.searchOnClear = (options.searchOnClear && !this.smallScreenEnabled);
if (Object.keys(options.groupHeaders).length > 0) {
const groupedCollection = groupDisplays(options.collection, options.groupHeaders);
@@ -707,7 +708,7 @@ hqDefine("cloudcare/js/formplayer/menus/views/query", function () {
childView.clear();
});
self.setStickyQueryInputs();
- if (self.dynamicSearchEnabled) {
+ if (self.dynamicSearchEnabled || this.searchOnClear) {
self.updateSearchResults();
}
},