-
-
Notifications
You must be signed in to change notification settings - Fork 218
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
Add Assigned Location Column to Application Status Report #34744
Changes from 16 commits
30a284a
de825b1
07b5828
c229c7a
d60fcbd
362e684
561afac
78bb53d
7ebeb72
c1a088b
37c70b4
e55ec3d
fd2f9be
ee88a55
d5b5728
581bfe1
ba975bf
b045a3d
d6a20e8
e5c2342
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
+++ | ||
@@ -1,5 +1,5 @@ | ||
'use strict'; | ||
-hqDefine("reports/js/bootstrap3/application_status", [ | ||
+hqDefine("reports/js/bootstrap5/application_status", [ | ||
"jquery", | ||
], function ( | ||
$ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ | |
ProjectReportParametersMixin, | ||
) | ||
from corehq.apps.reports.util import format_datatables_data | ||
from corehq.apps.users.models import CouchUser | ||
from corehq.apps.users.util import user_display_string | ||
from corehq.const import USER_DATE_FORMAT | ||
from corehq.util.quickcache import quickcache | ||
|
@@ -81,6 +82,10 @@ def _columns(self): | |
DataTablesColumn(_("Username"), | ||
prop_name='username.exact', | ||
sql_col='user_dim__username'), | ||
DataTablesColumn(_("Assigned Location(s)"), | ||
help_text=_('Assigned locations for the user, with the primary ' | ||
'location highlighted in bold.'), | ||
sortable=False), | ||
DataTablesColumn(_("Last Submission"), | ||
prop_name='reporting_metadata.last_submissions.submission_date', | ||
alt_prop_name='reporting_metadata.last_submission_for_user.submission_date', | ||
|
@@ -119,7 +124,7 @@ def headers(self): | |
sortable=False) | ||
) | ||
headers = DataTablesHeader(*columns) | ||
headers.custom_sort = [[1, 'desc']] | ||
headers.custom_sort = [[2, 'desc']] | ||
return headers | ||
|
||
@cached_property | ||
|
@@ -307,6 +312,16 @@ def include_location_data(self): | |
) | ||
) | ||
|
||
def user_locations_dict(self, user_docs): | ||
all_loc_ids = set() | ||
for user_doc in user_docs: | ||
user = CouchUser.wrap_correctly(user_doc) | ||
for loc_id in user.get_location_ids(self.domain): | ||
all_loc_ids.add(loc_id) | ||
return dict(SQLLocation.objects.filter( | ||
location_id__in=all_loc_ids, domain=self.domain | ||
).values_list('location_id', 'name')) | ||
|
||
def process_rows(self, users, fmt_for_export=False): | ||
rows = [] | ||
users = list(users) | ||
|
@@ -316,6 +331,7 @@ def process_rows(self, users, fmt_for_export=False): | |
grouped_ancestor_locs = self.get_bulk_ancestors(location_ids) | ||
self.required_loc_columns = self.get_location_columns(grouped_ancestor_locs) | ||
|
||
user_loc_dict = self.user_locations_dict(users) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: and then changing this variables name as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
for user in users: | ||
last_build = last_seen = last_sub = last_sync = last_sync_date = app_name = commcare_version = None | ||
last_build_profile_name = device = device_app_meta = num_unsent_forms = None | ||
|
@@ -373,6 +389,7 @@ def process_rows(self, users, fmt_for_export=False): | |
user_display_string(user.get('username', ''), | ||
user.get('first_name', ''), | ||
user.get('last_name', '')), | ||
self.get_location_column(user, user_loc_dict), | ||
_fmt_date(last_seen, fmt_for_export), _fmt_date(last_sync_date, fmt_for_export), | ||
app_name or "---", build_version, commcare_version or '---', | ||
num_unsent_forms if num_unsent_forms is not None else "---", | ||
|
@@ -477,12 +494,51 @@ def _fmt_timestamp(timestamp): | |
|
||
for row in table[1:]: | ||
# Last submission | ||
row[len(location_colums) + 1] = _fmt_timestamp(row[len(location_colums) + 1]) | ||
# Last sync | ||
row[len(location_colums) + 2] = _fmt_timestamp(row[len(location_colums) + 2]) | ||
# Last sync | ||
row[len(location_colums) + 3] = _fmt_timestamp(row[len(location_colums) + 3]) | ||
result[0][1] = table | ||
return result | ||
|
||
def get_location_column(self, user_doc, user_loc_dict): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: this could be a private function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in d6a20e8 |
||
user = CouchUser.wrap_correctly(user_doc) | ||
if not user.get_location_ids(self.domain): | ||
return '---' | ||
return self._get_formatted_assigned_location_names(user, user_loc_dict) | ||
|
||
def _get_formatted_assigned_location_names(self, user, user_loc_dict): | ||
""" | ||
Create an HTML formatted string of the given assigned location names. | ||
The primary location will be highlighted in bold. | ||
""" | ||
assigned_location_ids = user.get_location_ids(self.domain) | ||
primary_location_id = user.get_location_id(self.domain) | ||
formatted_loc_names = [] | ||
for loc_id in assigned_location_ids: | ||
loc_name = user_loc_dict.get(loc_id) | ||
if loc_id == primary_location_id: | ||
formatted_loc_names.insert( | ||
0, f'<strong>{loc_name}</strong>' | ||
) | ||
else: | ||
formatted_loc_names.append(loc_name) | ||
|
||
formatted_str = ', '.join(formatted_loc_names[:4]) | ||
html_nodes = [ | ||
f'<span class="locations-list">{formatted_str}</span>', | ||
] | ||
if len(formatted_loc_names) > 4: | ||
all_str = ', '.join(formatted_loc_names) | ||
view_controls_html_nodes = [ | ||
f'<span class="loc-view-control">{_("...See more")}</span>', | ||
f'<span class="loc-view-control" style="display:none">{_("...See less")}</span>', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I am not sure I have seen "See less" on such widgets before. Is "Collapse" a better word? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point. I have updated the text in b045a3d |
||
] | ||
html_nodes += [ | ||
f'<span class="all-locations-list" style="display:none">{all_str}</span>', | ||
f'<a href="#" class="toggle-all-locations">{"".join(view_controls_html_nodes)}</a>', | ||
] | ||
return format_html(f'<div>{"".join(html_nodes)}</div>') | ||
|
||
|
||
def _get_commcare_version(app_version_info): | ||
commcare_version = ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use strict'; | ||
hqDefine("reports/js/bootstrap3/application_status", [ | ||
"jquery", | ||
], function ( | ||
$ | ||
) { | ||
$(function () { | ||
$('#report-content').on('click', '.toggle-all-locations', function (e) { | ||
$(this).prevAll('.locations-list').toggle(); | ||
$(this).children('.loc-view-control').toggle(); | ||
$(this).prevAll('.all-locations-list').toggle(); | ||
e.preventDefault(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use strict'; | ||
hqDefine("reports/js/bootstrap5/application_status", [ | ||
"jquery", | ||
], function ( | ||
$ | ||
) { | ||
$(function () { | ||
$('#report-content').on('click', '.toggle-all-locations', function (e) { | ||
$(this).prevAll('.locations-list').toggle(); | ||
$(this).children('.loc-view-control').toggle(); | ||
$(this).prevAll('.all-locations-list').toggle(); | ||
e.preventDefault(); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: a docstring would be useful here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'd suggest naming this to locations_names_dict instead considering what its returning and its not really bound to users at all other than just getting the location IDs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. Addressed in ba975bf