Skip to content

Commit

Permalink
Merge pull request #33738 from dimagi/jt/inline_case_search_parent_se…
Browse files Browse the repository at this point in the history
…lect

Inline Case Search Parent Select
  • Loading branch information
Jtang-1 committed Dec 13, 2023
2 parents 8014b53 + ba15267 commit eeed63e
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 106 deletions.
28 changes: 13 additions & 15 deletions corehq/apps/app_manager/helpers/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,27 +406,25 @@ def validate_parent_select(self):
from corehq.apps.app_manager.views.modules import get_all_case_modules
valid_modules = get_all_case_modules(self.app, self.module)
valid_module_ids = [info['unique_id'] for info in valid_modules]
search_config = getattr(self.module, 'search_config', None)
if self.module.parent_select.module_id not in valid_module_ids:
errors.append({
'type': 'invalid parent select id',
'module': self.get_module_info(),
})
else:
module_id = self.module.parent_select.module_id
parent_select_module = self.module.get_app().get_module_by_unique_id(module_id)
if parent_select_module and module_uses_inline_search(parent_select_module):
errors.append({
'type': 'parent select is inline search module',
'module': self.get_module_info(),
})

if module_uses_inline_search(self.module):
if self.module.parent_select.relationship:
errors.append({
'type': 'inline search parent select relationship',
'module': self.get_module_info(),
})

elif search_config:
parent_module_id = self.module.parent_select.module_id
parent_select_module = self.module.get_app().get_module_by_unique_id(parent_module_id)
if parent_select_module and module_uses_inline_search(parent_select_module):
parent_module_instance_name = parent_select_module.search_config.get_instance_name()
if search_config.get_instance_name() == parent_module_instance_name:
errors.append({
'type': 'non-unique instance name with parent select module',
"message": f'The instance "{search_config.get_instance_name()}" is not unique',
"module": self.get_module_info(),
"details": search_config.get_instance_name()
})
return errors

def validate_smart_links(self):
Expand Down
2 changes: 1 addition & 1 deletion corehq/apps/app_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2189,7 +2189,7 @@ def get_instance_name(self):

def get_relevant(self, case_session_var, multi_select=False):
xpath = CaseClaimXpath(case_session_var)
default_condition = xpath.multi_select_relevant() if multi_select else xpath.default_relevant()
default_condition = xpath.multi_case_relevant() if multi_select else xpath.default_relevant()
if self.additional_relevant:
return f"({default_condition}) and ({self.additional_relevant})"
return default_condition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
module_offers_registry_search,
module_uses_inline_search,
module_uses_include_all_related_cases,
module_uses_inline_search_with_parent_relationship_parent_select,
)
from corehq.apps.app_manager.xpath import (
CaseClaimXpath,
Expand All @@ -82,6 +83,7 @@
CASE_SEARCH_REGISTRY_ID_KEY,
CASE_SEARCH_INCLUDE_ALL_RELATED_CASES_KEY,
CASE_SEARCH_SORT_KEY,
CASE_SEARCH_XPATH_QUERY_KEY,
)
from corehq.util.timer import time_method
from corehq.util.view_utils import absolute_reverse
Expand Down Expand Up @@ -153,6 +155,9 @@ def build_case_id_query_data(self):
data.exclude = self._get_multi_select_exclude()
else:
data.ref = QuerySessionXPath(self.case_session_var).instance()
if (not self.exclude_relevant
and module_uses_inline_search_with_parent_relationship_parent_select(self.module)):
data.exclude = CaseIDXPath(data.ref).case().count().neq(0)
return data

def _get_multi_select_nodeset(self):
Expand Down Expand Up @@ -295,6 +300,17 @@ def _remote_request_query_datums(self):
ref=f"'{','.join(refs)}'",
)
)
if module_uses_inline_search_with_parent_relationship_parent_select(self.module):
parent_module_id = self.module.parent_select.module_id
parent_module = self.app.get_module_by_unique_id(parent_module_id)
parent_case_type = parent_module.case_type
datums.append(
QueryData(
key=CASE_SEARCH_XPATH_QUERY_KEY,
ref=f"\"ancestor-exists(parent, @case_type='{parent_case_type}')\""
)
)

return datums

def build_query_prompts(self):
Expand Down Expand Up @@ -440,7 +456,7 @@ def __init__(self, suite, module, detail_section_elements, endpoint_id, case_ses
def get_post_relevant(self):
xpath = CaseClaimXpath(self.case_session_var)
if self.module.is_multi_select():
return xpath.multi_select_relevant()
return xpath.multi_case_relevant()
return xpath.default_relevant()

def build_command(self):
Expand Down
12 changes: 12 additions & 0 deletions corehq/apps/app_manager/suite_xml/sections/entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
module_loads_registry_case,
module_offers_search,
module_uses_inline_search,
module_uses_inline_search_with_parent_relationship_parent_select,
)
from corehq.apps.app_manager.xform import (
autoset_owner_id_for_advanced_action,
autoset_owner_id_for_open_case,
autoset_owner_id_for_subcase,
)
from corehq.apps.app_manager.xpath import (
CaseClaimXpath,
CaseIDXPath,
ItemListFixtureXpath,
ProductInstanceXpath,
Expand Down Expand Up @@ -248,6 +250,7 @@ def include_post_in_entry(self, module_id):

def add_post_to_entry(self, form, module, e):
from ..post_process.remote_requests import (
QuerySessionXPath,
RemoteRequestFactory,
)
case_session_var = self.get_case_session_var_for_form(form)
Expand All @@ -257,6 +260,15 @@ def add_post_to_entry(self, form, module, e):
None, module, [], case_session_var=case_session_var, storage_instance=storage_instance,
exclude_relevant=case_search_sync_cases_on_form_entry_enabled_for_domain(self.app.domain))
e.post = remote_request_factory.build_remote_request_post()
if module_uses_inline_search_with_parent_relationship_parent_select(module):
case_datum_ids = [form_datum.datum.id for form_datum in self.get_case_datums_basic_module(module, form)
if (form_datum.datum.id != case_session_var and not form_datum.is_new_case_id)]
for case_datum_id in case_datum_ids:
data = QueryData(key='case_id')
data.ref = QuerySessionXPath(case_datum_id).instance()
data.exclude = CaseIDXPath(data.ref).case().count().neq(0)
e.post.data.append(data)
e.post.relevant = CaseClaimXpath.multi_case_relevant()

def entry_for_module(self, module):
# avoid circular dependency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,14 @@ <h4 class="alert-heading">
{% blocktrans with module_name=error.module.name|trans:langs %}
The case list in <a href="{{ module_url }}">{{ module_name }}</a> can not use the same "search input instance name" as its Parent Menu.
{% endblocktrans %}
{% case "inline search to display only forms" %}
{% blocktrans with module_name=error.module.name|trans:langs %}
<a href="{{ module_url }}">{{ module_name }}</a>
uses "Display only forms" and is also configured with
"make search input available after search". This workflow is unsupported.
{% endblocktrans %}
{% case "parent select is inline search module" %}
{% case "non-unique instance name with parent select module" %}
{% blocktrans with module_name=error.module.name|trans:langs %}
<a href="{{ module_url }}">{{ module_name }}</a>
uses parent case selection but parent case list is using
"make search input available after search". This workflow is unsupported.
The case list in <a href="{{ module_url }}">{{ module_name }}</a> can not use the same "search input instance name" as its Parent Select Menu.
{% endblocktrans %}
{% case "inline search parent select relationship" %}
{% case "inline search to display only forms" %}
{% blocktrans with module_name=error.module.name|trans:langs %}
<a href="{{ module_url }}">{{ module_name }}</a>
uses parent case selection and is configured with
uses "Display only forms" and is also configured with
"make search input available after search". This workflow is unsupported.
{% endblocktrans %}
{% case "circular case hierarchy" %}
Expand Down
38 changes: 0 additions & 38 deletions corehq/apps/app_manager/tests/test_build_errors_inline_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,44 +86,6 @@ def test_inline_search_previous_screen(self, *args):

self.assertIn("workflow previous inline search", _get_error_types(factory.app))

def test_parent_select_to_inline_search(self, *args):
"""an inline module can't be the target of parent select"""
factory = AppFactory(build_version='2.51.0')
m0, _ = factory.new_basic_module('first', 'case')

m0.search_config = CaseSearch(
search_label=CaseSearchLabel(label={'en': 'Search'}),
properties=[CaseSearchProperty(name=field) for field in ['name', 'greatest_fear']],
auto_launch=True,
inline_search=True,
)

m1, _ = factory.new_basic_module('second', 'case')
m1.parent_select.active = True
m1.parent_select.relationship = None
m1.parent_select.module_id = m0.get_or_create_unique_id()

self.assertIn("parent select is inline search module", _get_error_types(factory.app))

def test_parent_select_of_inline_search_module(self, *args):
"""inline search can't use parent select with relationship='parent'"""
factory = AppFactory(build_version='2.51.0')
m0, _ = factory.new_basic_module('first', 'case')

m0.search_config = CaseSearch(
search_label=CaseSearchLabel(label={'en': 'Search'}),
properties=[CaseSearchProperty(name=field) for field in ['name', 'greatest_fear']],
auto_launch=True,
inline_search=True,
)

m1, _ = factory.new_basic_module('second', 'case')

m0.parent_select.active = True
m0.parent_select.module_id = m0.get_or_create_unique_id()

self.assertIn("inline search parent select relationship", _get_error_types(factory.app))


def _get_error_types(app):
return [error['type'] for error in app.validate_app()]

0 comments on commit eeed63e

Please sign in to comment.