Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support translatable words within calculated properties in case tiles #34809

Merged
merged 11 commits into from
Aug 8, 2024
2 changes: 1 addition & 1 deletion corehq/apps/app_manager/app_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def _create_module_details_app_strings(module, langs):
clean_trans(column.header, langs)
)

if column.format in ('enum', 'conditional-enum', 'enum-image', 'clickable-icon'):
if column.format in ('enum', 'conditional-enum', 'enum-image', 'clickable-icon', 'translatable-enum'):
for item in column.enum:
yield (
id_strings.detail_column_enum_variable(
Expand Down
35 changes: 30 additions & 5 deletions corehq/apps/app_manager/detail_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,7 @@ def template(self):
form=self.template_form,
width=self.template_width,
)

if self.column.useXpathExpression:
if self.column.useXpathExpression and self.column.format != 'translatable-enum':
xpath = sx.CalculatedPropertyXPath(function=self.xpath)
if re.search(r'\$lang', self.xpath):
xpath.variables.node.append(
Expand Down Expand Up @@ -192,8 +191,9 @@ def sort_node(self):
locale_id=self.id_strings.current_language()
).node
)
xpath_variable = sx.XPathVariable(name='calculated_property', xpath=xpath)
sort.text.xpath.variables.node.append(xpath_variable.node)
if self.column.format != 'translatable-enum':
xpath_variable = sx.XPathVariable(name='calculated_property', xpath=xpath)
sort.text.xpath.variables.node.append(xpath_variable.node)

if self.sort_element:
if not sort:
Expand Down Expand Up @@ -307,7 +307,8 @@ def fields(self):
endpoint_action=self.action,
alt_text=self.alt_text,
)
elif self.sort_xpath_function and self.detail.display == 'short':
elif (self.sort_xpath_function and self.detail.display == 'short'
and self.column.format != 'translatable-enum'):
yield sx.Field(
style=self.style,
header=self.header,
Expand Down Expand Up @@ -517,6 +518,30 @@ def _xpath_template_context(self, type):
}


@register_format_type('translatable-enum')
class TranslatableEnum(Enum):
@property
def sort_node(self):
node = super(TranslatableEnum, self).sort_node
if node:
variables = self.variables
for key in variables:
node.text.xpath.node.append(
sx.XPathVariable(name=key, locale_id=variables[key]).node
)
return node

def _make_xpath(self, type):
return sx.XPathEnum.build(
enum=self.column.enum,
format=self.column.format,
type=type,
template=None,
get_template_context=lambda: {'calculated_property': self.xpath},
get_value=lambda key: self.id_strings.detail_column_enum_variable(self.module, self.detail_type,
self.column, key))


@register_format_type('late-flag')
class LateFlag(HideShortHeaderColumn):
template_width = "11%"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
/**
* Model for a column in the Display Properties section of case list/detail.
*
Expand Down Expand Up @@ -231,6 +232,9 @@ hqDefine("app_manager/js/details/column", function () {
}
}
}
} else {
// Restrict Translatable Text usage to Calculated Properties only
menuOptions.splice(-1);
}

self.format = uiElement.select(menuOptions).val(self.original.format || null);
Expand All @@ -245,6 +249,7 @@ hqDefine("app_manager/js/details/column", function () {
multimedia: self.screen.config.multimedia,
values_are_icons: self.original.format === 'enum-image',
keys_are_conditions: self.original.format === 'conditional-enum',
values_are_translatable: self.original.format === 'translatable-enum',
};
self.enum_extra = uiElement.key_value_mapping(o);
}());
Expand Down Expand Up @@ -394,9 +399,11 @@ hqDefine("app_manager/js/details/column", function () {
fireChange();
});
self.date_extra.value = format.val();
} else if (this.val() === "enum" || this.val() === "enum-image" || this.val() === 'conditional-enum') {
} else if (this.val() === "enum" || this.val() === "enum-image"
|| this.val() === 'conditional-enum' || this.val() === 'translatable-enum') {
self.enum_extra.values_are_icons(this.val() === 'enum-image');
self.enum_extra.keys_are_conditions(this.val() === 'conditional-enum');
self.enum_extra.values_are_translatable(this.val() === 'translatable-enum');
self.format.ui.parent().append(self.enum_extra.ui);
} else if (this.val() === "clickable-icon") {
self.enum_extra.values_are_icons(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
/* globals DOMPurify */
/**
* Contains a few UI utilities for the Display Properties
Expand Down Expand Up @@ -80,6 +81,12 @@ hqDefine("app_manager/js/details/utils", function () {
label: gettext('Conditional ID Mapping'),
});
}
if (addOns.calc_xpaths) {
formats.push({
value: "translatable-enum",
label: gettext('Translatable Text'),
});
}

if (hqImport('hqwebapp/js/toggles').toggleEnabled('VELLUM_CASE_MICRO_IMAGE')) {
formats.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style horz-align="left" vert-align="center" font-size="small">
<grid grid-height="1" grid-width="12" grid-x="0" grid-y="0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style horz-align="center" vert-align="top" font-size="small">
<grid grid-height="1" grid-width="1" grid-x="0" grid-y="0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style horz-align="left" vert-align="center" font-size="small" show-border="true">
<grid grid-height="1" grid-width="12" grid-x="0" grid-y="0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style
horz-align="left"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style horz-align="left" vert-align="center" font-size="medium">
<grid grid-height="1" grid-width="12" grid-x="0" grid-y="0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style horz-align="left" vert-align="center" font-size="small">
<grid grid-height="1" grid-width="12" grid-x="0" grid-y="0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<field>
<style
horz-align="center"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<locale id="{title_text_id}"/>
</text>
</title>

<variables>
{custom_variables}
</variables>
<action>
<display>
<text>
Expand Down
27 changes: 22 additions & 5 deletions corehq/apps/app_manager/suite_xml/features/case_tiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from corehq.apps.app_manager import id_strings
from corehq.apps.app_manager.exceptions import SuiteError
from corehq.apps.app_manager.suite_xml.xml_models import (
Detail, XPathVariable, TileGroup, Style, EndpointAction
Detail, DetailVariable, XPathVariable, TileGroup, Style, EndpointAction
)

TILE_DIR = Path(__file__).parent.parent / "case_tile_templates"
Expand Down Expand Up @@ -113,6 +113,7 @@ def build_case_tile_detail(self, detail, start, end):
for template_field in case_tile_template_config(self.detail.case_tile_template).fields:
column = self._get_matched_detail_column(template_field)
context[template_field] = self._get_column_context(column)
context['custom_variables'] = self._get_custom_variables(self.detail.custom_variables_dict)

# Populate the template
detail_as_string = self._case_tile_template_string.format(**context)
Expand Down Expand Up @@ -181,14 +182,14 @@ def _get_column_context(self, column):
"prefix": escape(
column.header.get(default_lang, "")
),
"format": column.format
"format": column.format,
"variables": '',
"endpoint_action": '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was endpoint_action just missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, both variables and endpoint_action were set as blank strings later down the function so I just grouped them into the initial dictionary creation

}

context['variables'] = ''
if column.format in ["enum", "conditional-enum", "enum-image", "clickable-icon"]:
if column.format in ["enum", "conditional-enum", "enum-image", "clickable-icon", "translatable-enum"]:
context["variables"] = self._get_enum_variables(column)

context['endpoint_action'] = ''
if column.endpoint_action_id:
context["endpoint_action"] = self._get_endpoint_action(column.endpoint_action_id)
return context
Expand All @@ -200,6 +201,10 @@ def _get_xpath_function(self, column):
else:
xpath_function = self._escape_xpath_function(get_column_generator(
self.app, self.module, self.detail, column).xpath_function)
if column.format == "translatable-enum":
for enum in column.enum:
if enum.key in xpath_function and 'k' + enum.key not in xpath_function:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the 'k'? I am confused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when adding the enum keys to the app_strings file, it always uses key_as_variable which prepends a k to the variable name so it won't start with a numeral/be a valid xml variable. I don't want the user to always have to add k when referencing the variable so I'm correcting it in the backend instead so that a calculation like concat($test) is actually read as concat($ktest) which maps to a valid string in the app_strings file.

Looking at it again... I definitely could've just made it so it doesn't prepend k for translatable-text formats but I guess it's nice that you could potentially start a key name with a number and you could reuse keys you use for custom variables without it overlapping.

xpath_function = xpath_function.replace(enum.key, 'k' + enum.key)
return xpath_function

@staticmethod
Expand Down Expand Up @@ -274,3 +279,15 @@ def _compare_fields_by_order(initial_field, incoming_field):
elif initial_field.sort_node.order is None:
return incoming_field
return min(initial_field, incoming_field, key=lambda field: field.sort_node.order)

@staticmethod
def _get_custom_variables(custom_var_dict):
variables = []
for var_name, var_function in custom_var_dict.items():
variables.append(
DetailVariable(
name=var_name,
function=var_function
).serialize()
)
return ''.join([bytes(variable).decode('utf-8') for variable in variables])
17 changes: 13 additions & 4 deletions corehq/apps/app_manager/suite_xml/xml_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,23 @@ def build(cls, enum, format, type, template, get_template_context, get_value):
v_val = get_value(v_key)
variables.append(XPathVariable(name=v_key, locale_id=v_val))
parts = []
for i, item in enumerate(enum):
template_context = get_template_context(item, i)
parts.append(template.format(**template_context))
if format == 'translatable-enum':
calculated_property = get_template_context()['calculated_property']
# converting variables into suite.xml recognized variables (i.e. $variable > $kvariable)
for item in enum:
key = item.key_as_variable
if key[1:] in calculated_property:
calculated_property = calculated_property.replace(key[1:], key)
parts.append(calculated_property)
else:
for i, item in enumerate(enum):
template_context = get_template_context(item, i)
parts.append(template.format(**template_context))
if type == "display" and format == "enum":
parts.insert(0, "replace(join(' ', ")
parts[-1] = parts[-1][:-2] # removes extra comma from last string
parts.append("), '\\s+', ' ')")
else:
elif format != "translatable-enum":
parts.append("''")
parts.append(")" * len(enum))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@
<locale id="cchq.case"/>
</text>
</title>
<variables>

</variables>
<action>
<display>
<text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
<locale id="cchq.case"/>
</text>
</title>
<variables>

</variables>
<action>
<display>
<text>
Expand Down
Loading
Loading