mirror of https://github.com/zulip/zulip.git
activity: Add totals row as sticky footer to activity charts.
Updates the total row for the installation and remote activity charts to be in the table footer. Makes the footer class sticky to the bottom of the view so that it is always visible on the chart. Also, updates the installation activity column for revenue to be formatted as a dollar string, since this formatting was being applied in the updated total row.
This commit is contained in:
parent
5786a38cec
commit
bfd9eec4b3
|
@ -31,6 +31,8 @@ def make_table(
|
||||||
title: str,
|
title: str,
|
||||||
cols: Sequence[str],
|
cols: Sequence[str],
|
||||||
rows: Sequence[Any],
|
rows: Sequence[Any],
|
||||||
|
*,
|
||||||
|
totals: Optional[Any] = None,
|
||||||
stats_link: Optional[Markup] = None,
|
stats_link: Optional[Markup] = None,
|
||||||
has_row_class: bool = False,
|
has_row_class: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
@ -41,7 +43,7 @@ def make_table(
|
||||||
|
|
||||||
rows = list(map(fix_row, rows))
|
rows = list(map(fix_row, rows))
|
||||||
|
|
||||||
data = dict(title=title, cols=cols, rows=rows, stats_link=stats_link)
|
data = dict(title=title, cols=cols, rows=rows, totals=totals, stats_link=stats_link)
|
||||||
|
|
||||||
content = loader.render_to_string(
|
content = loader.render_to_string(
|
||||||
"analytics/ad_hoc_query.html",
|
"analytics/ad_hoc_query.html",
|
||||||
|
|
|
@ -23,6 +23,7 @@ from analytics.views.activity_common import (
|
||||||
realm_url_link,
|
realm_url_link,
|
||||||
)
|
)
|
||||||
from analytics.views.support import get_plan_type_string
|
from analytics.views.support import get_plan_type_string
|
||||||
|
from corporate.lib.stripe import cents_to_dollar_string
|
||||||
from zerver.decorator import require_server_admin
|
from zerver.decorator import require_server_admin
|
||||||
from zerver.lib.request import has_request_variables
|
from zerver.lib.request import has_request_variables
|
||||||
from zerver.models import Realm
|
from zerver.models import Realm
|
||||||
|
@ -210,7 +211,7 @@ def realm_summary_table() -> str:
|
||||||
string_id = row["string_id"]
|
string_id = row["string_id"]
|
||||||
|
|
||||||
if string_id in estimated_arrs:
|
if string_id in estimated_arrs:
|
||||||
row["arr"] = estimated_arrs[string_id]
|
row["arr"] = f"${cents_to_dollar_string(estimated_arrs[string_id])}"
|
||||||
|
|
||||||
if row["plan_type"] in [Realm.PLAN_TYPE_STANDARD, Realm.PLAN_TYPE_PLUS]:
|
if row["plan_type"] in [Realm.PLAN_TYPE_STANDARD, Realm.PLAN_TYPE_PLUS]:
|
||||||
row["effective_rate"] = 100 - int(realms_with_default_discount.get(string_id, 0))
|
row["effective_rate"] = 100 - int(realms_with_default_discount.get(string_id, 0))
|
||||||
|
@ -250,28 +251,34 @@ def realm_summary_table() -> str:
|
||||||
total_bot_count += int(row["bot_count"])
|
total_bot_count += int(row["bot_count"])
|
||||||
total_wau_count += int(row["wau_count"])
|
total_wau_count += int(row["wau_count"])
|
||||||
|
|
||||||
total_row = dict(
|
total_row = [
|
||||||
string_id="Total",
|
"Total",
|
||||||
plan_type_string="",
|
"",
|
||||||
org_type_string="",
|
"",
|
||||||
effective_rate="",
|
"",
|
||||||
arr=total_arr,
|
f"${cents_to_dollar_string(total_arr)}",
|
||||||
realm_url="",
|
"",
|
||||||
stats_link="",
|
"",
|
||||||
support_link="",
|
total_dau_count,
|
||||||
date_created_day="",
|
total_wau_count,
|
||||||
dau_count=total_dau_count,
|
total_user_profile_count,
|
||||||
user_profile_count=total_user_profile_count,
|
total_bot_count,
|
||||||
bot_count=total_bot_count,
|
"",
|
||||||
wau_count=total_wau_count,
|
"",
|
||||||
)
|
"",
|
||||||
|
"",
|
||||||
rows.insert(0, total_row)
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
|
||||||
content = loader.render_to_string(
|
content = loader.render_to_string(
|
||||||
"analytics/realm_summary_table.html",
|
"analytics/realm_summary_table.html",
|
||||||
dict(
|
dict(
|
||||||
rows=rows,
|
rows=rows,
|
||||||
|
totals=total_row,
|
||||||
num_active_sites=num_active_sites,
|
num_active_sites=num_active_sites,
|
||||||
utctime=now.strftime("%Y-%m-%d %H:%M %Z"),
|
utctime=now.strftime("%Y-%m-%d %H:%M %Z"),
|
||||||
billing_enabled=settings.BILLING_ENABLED,
|
billing_enabled=settings.BILLING_ENABLED,
|
||||||
|
|
|
@ -145,7 +145,7 @@ def realm_user_summary_table(
|
||||||
return row["cells"][4]
|
return row["cells"][4]
|
||||||
|
|
||||||
rows = sorted(rows, key=by_last_heard_from, reverse=True)
|
rows = sorted(rows, key=by_last_heard_from, reverse=True)
|
||||||
content = make_table(title, cols, rows, stats_link, has_row_class=True)
|
content = make_table(title, cols, rows, stats_link=stats_link, has_row_class=True)
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -214,9 +214,8 @@ def get_remote_server_activity(request: HttpRequest) -> HttpResponse:
|
||||||
total_row.append(str(sum(row[i] for row in rows if row[i] is not None)))
|
total_row.append(str(sum(row[i] for row in rows if row[i] is not None)))
|
||||||
else:
|
else:
|
||||||
total_row.append("")
|
total_row.append("")
|
||||||
rows.insert(0, total_row)
|
|
||||||
|
|
||||||
content = make_table(title, cols, rows)
|
content = make_table(title, cols, rows, totals=total_row)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"analytics/activity_details_template.html",
|
"analytics/activity_details_template.html",
|
||||||
|
|
|
@ -70,7 +70,7 @@ def estimate_annual_recurring_revenue_by_realm() -> Dict[str, int]: # nocoverag
|
||||||
).get_customer_plan_renewal_amount(plan, latest_ledger_entry)
|
).get_customer_plan_renewal_amount(plan, latest_ledger_entry)
|
||||||
if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_MONTHLY:
|
if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_MONTHLY:
|
||||||
renewal_cents *= 12
|
renewal_cents *= 12
|
||||||
annual_revenue[plan.customer.realm.string_id] = int(renewal_cents / 100)
|
annual_revenue[plan.customer.realm.string_id] = renewal_cents
|
||||||
return annual_revenue
|
return annual_revenue
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,4 +23,11 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
{% if data.totals %}
|
||||||
|
<tfoot class="activity-foot">
|
||||||
|
{% for total in data.totals %}
|
||||||
|
<td>{{ total }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tfoot>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -121,5 +121,9 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tfoot class="activity-foot">
|
||||||
|
{% for total in totals %}
|
||||||
|
<td>{{ total }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -12,6 +12,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.activity-foot {
|
||||||
|
background-color: hsl(208deg 100% 97%);
|
||||||
|
font-weight: 700;
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.table-striped {
|
.table-striped {
|
||||||
& tr.recently_active {
|
& tr.recently_active {
|
||||||
& td {
|
& td {
|
||||||
|
|
Loading…
Reference in New Issue