-
Notifications
You must be signed in to change notification settings - Fork 25
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
Rework the histogram activity chart #5685
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
---|---|---|
|
@@ -19,10 +19,11 @@ | |
from django.conf import settings | ||
from django.contrib.humanize.templatetags import humanize | ||
from django.core.exceptions import ValidationError | ||
from django.db.models import Max, Min, Sum | ||
from django.db.models import Min, Sum | ||
from django.db.models.functions import Lower | ||
from django.http import Http404, HttpResponse, HttpResponseRedirect, JsonResponse | ||
from django.urls import reverse | ||
from django.utils import timezone | ||
from django.utils.encoding import force_str | ||
from django.utils.functional import cached_property | ||
from django.utils.translation import gettext_lazy as _, ngettext_lazy as _p | ||
|
@@ -1146,12 +1147,6 @@ | |
) | ||
|
||
class ActivityData(BaseReadView): | ||
# the min number of responses to show a histogram | ||
HISTOGRAM_MIN = 0 | ||
|
||
# the min number of responses to show the period charts | ||
PERIOD_MIN = 0 | ||
|
||
permission = "flows.flow_results" | ||
|
||
day_names = ( | ||
|
@@ -1164,7 +1159,7 @@ | |
_("Saturday"), | ||
) | ||
|
||
def get_day_of_week_counts(self, exit_uuids: list) -> dict: | ||
def get_day_of_week_counts(self, exit_uuids: list) -> dict[int, int]: | ||
dow = ( | ||
self.object.path_counts.filter(from_uuid__in=exit_uuids) | ||
.extra({"day": "extract(dow from period::timestamp)"}) | ||
|
@@ -1174,7 +1169,7 @@ | |
|
||
return {int(d.get("day")): d.get("count") for d in dow} | ||
|
||
def get_hour_of_day_counts(self, exit_uuids: list) -> dict: | ||
def get_hour_of_day_counts(self, exit_uuids: list) -> dict[int, int]: | ||
hod = ( | ||
self.object.path_counts.filter(from_uuid__in=exit_uuids) | ||
.extra({"hour": "extract(hour from period::timestamp)"}) | ||
|
@@ -1185,14 +1180,21 @@ | |
|
||
return {int(h.get("hour")): h.get("count") for h in hod} | ||
|
||
def get_date_counts(self, exit_uuids: list, truncate: str) -> list[tuple]: | ||
dates = ( | ||
self.object.path_counts.filter(from_uuid__in=exit_uuids) | ||
.extra({"date": f"date_trunc('{truncate}', period::date)"}) | ||
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. we should be able to replicate this with new counts by doing something similiar to how we extract team id from scope for tickert counts by team |
||
.values("date") | ||
.annotate(count=Sum("count")) | ||
.order_by("date") | ||
) | ||
|
||
return [(d.get("date"), d.get("count")) for d in dates] | ||
|
||
def render_to_response(self, context, **response_kwargs): | ||
total_responses = 0 | ||
flow = self.object | ||
|
||
exit_uuids = flow.metadata["waiting_exit_uuids"] | ||
dates = self.object.path_counts.filter(from_uuid__in=exit_uuids).aggregate(Max("period"), Min("period")) | ||
start_date = dates.get("period__min") | ||
end_date = dates.get("period__max") | ||
|
||
hour_dict = self.get_hour_of_day_counts(exit_uuids) | ||
hours = [] | ||
|
@@ -1206,34 +1208,33 @@ | |
dow.append({"name": x, "msgs": day_count}) | ||
total_responses += day_count | ||
|
||
if total_responses > self.PERIOD_MIN: | ||
dow = sorted(dow, key=lambda k: k["name"]) | ||
dow = [ | ||
{ | ||
"name": self.day_names[d["name"]], | ||
"msgs": d["msgs"], | ||
"y": 100 * float(d["msgs"]) / float(total_responses), | ||
} | ||
for d in dow | ||
] | ||
|
||
min_date = None | ||
histogram = [] | ||
|
||
if total_responses > self.HISTOGRAM_MIN: | ||
# our main histogram | ||
date_range = end_date - start_date | ||
histogram = self.object.path_counts.filter(from_uuid__in=exit_uuids) | ||
dow = [ | ||
{ | ||
"name": self.day_names[d["name"]], | ||
"msgs": d["msgs"], | ||
"y": 100 * float(d["msgs"]) / float(total_responses), | ||
} | ||
for d in dow | ||
] | ||
|
||
# figure out the earliest date we have data for | ||
min_date = self.object.path_counts.filter(from_uuid__in=exit_uuids).aggregate(Min("period")) | ||
min_date = min_date.get("period__min") | ||
if min_date: | ||
min_date = min_date.date() | ||
else: | ||
min_date = timezone.now().date() - timedelta(days=30) | ||
|
||
if date_range < timedelta(days=500): | ||
histogram = histogram.extra({"bucket": "date_trunc('day', period)"}) | ||
min_date = end_date - timedelta(days=100) | ||
else: | ||
histogram = histogram.extra({"bucket": "date_trunc('week', period)"}) | ||
min_date = end_date - timedelta(days=500) | ||
# bucket dates into months or weeks depending on the range | ||
if min_date < timezone.now().date() - timedelta(days=365 * 3): | ||
truncate = "month" | ||
elif min_date < timezone.now().date() - timedelta(days=365): | ||
truncate = "week" | ||
else: | ||
truncate = "day" | ||
|
||
histogram = histogram.values("bucket").annotate(count=Sum("count")).order_by("bucket") | ||
histogram = [[_["bucket"], _["count"]] for _ in histogram] | ||
dates = self.get_date_counts(exit_uuids, truncate) | ||
min_date = dates[0][0] if dates else timezone.now().date() - timedelta(days=30) | ||
|
||
summary = { | ||
"responses": total_responses, | ||
|
@@ -1279,13 +1280,11 @@ | |
|
||
return JsonResponse( | ||
{ | ||
"start_date": start_date, | ||
"end_date": end_date, | ||
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. not used |
||
"min_date": min_date, | ||
"summary": summary, | ||
"dow": dow, | ||
"hod": hours, | ||
"histogram": histogram, | ||
"histogram": dates, | ||
"completion": completion, | ||
}, | ||
json_dumps_params={"indent": 2}, | ||
|
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.
these are always zero...