first round

This commit is contained in:
Beverly Nguyen
2025-01-06 16:31:52 -08:00
parent 51e4fb3789
commit a3db0a9fc0
10 changed files with 74 additions and 43 deletions

View File

@@ -5,6 +5,7 @@
const COLORS = {
delivered: '#0076d6',
failed: '#fa9441',
pending: '#808080',
text: '#666'
};
@@ -45,7 +46,8 @@
// Show legend if there are messages
const legendData = [
{ label: 'Delivered', color: COLORS.delivered },
{ label: 'Failed', color: COLORS.failed }
{ label: 'Failed', color: COLORS.failed },
{ label: 'Pending', color: COLORS.pending }
];
const legendItem = legendContainer.selectAll('.legend-item')
@@ -100,12 +102,13 @@
const stackData = labels.map((label, i) => ({
label: label,
delivered: deliveredData[i],
failed: failedData[i] || 0 // Ensure there's a value for failed, even if it's 0
failed: failedData[i] || 0, // Ensure there's a value for failed, even if it's 0
pending: pendingData[i] || 0
}));
// Stack the data
const stack = d3.stack()
.keys(['delivered', 'failed'])
.keys(['delivered', 'failed', 'pending'])
.order(d3.stackOrderNone)
.offset(d3.stackOffsetNone);
@@ -113,8 +116,8 @@
// Color scale
const color = d3.scaleOrdinal()
.domain(['delivered', 'failed'])
.range([COLORS.delivered, COLORS.failed]);
.domain(['delivered', 'failed', 'pending'])
.range([COLORS.delivered, COLORS.failed, COLORS.pending]);
// Create bars with animation
const barGroups = svg.selectAll('.bar-group')
@@ -164,7 +167,7 @@
// Create table header
const headerRow = document.createElement('tr');
const headers = ['Day', 'Delivered', 'Failed'];
const headers = ['Day', 'Delivered', 'Failed', 'Pending'];
headers.forEach(headerText => {
const th = document.createElement('th');
th.textContent = headerText;
@@ -187,6 +190,10 @@
cellFailed.textContent = failedData[index];
row.appendChild(cellFailed);
const cellPending = document.createElement('td');
cellPending.textContent = pendingData[index];
row.appendChild(cellPending);
tbody.appendChild(row);
});
@@ -213,6 +220,7 @@
labels = [];
deliveredData = [];
failedData = [];
pendingData = [];
let totalMessages = 0;
@@ -224,7 +232,7 @@
labels.push(formattedDate);
deliveredData.push(data[dateString].sms.delivered);
failedData.push(data[dateString].sms.failure);
pendingData.push(data[dateString].sms.pending || 0);
// Calculate the total number of messages
totalMessages += data[dateString].sms.delivered + data[dateString].sms.failure;
}
@@ -260,7 +268,7 @@
})
.catch(error => console.error('Error fetching daily stats:', error));
};
// setInterval(() => fetchData('service'), 1000);
const handleDropdownChange = function(event) {
const selectedValue = event.target.value;
const subTitle = document.querySelector(`#activityChartContainer .chart-subtitle`);

View File

@@ -493,7 +493,7 @@ def message_count_noun(count, template_type):
def message_count(count, template_type):
return f"{format_thousands(count)} " f"{message_count_noun(count, template_type)}"
return f"format_message_count{format_thousands(count)} " f"{message_count_noun(count, template_type)}"
def recipient_count_label(count, template_type):

View File

@@ -48,16 +48,8 @@ def service_dashboard(service_id):
if not current_user.has_permissions("view_activity"):
return redirect(url_for("main.choose_template", service_id=service_id))
yearly_usage = billing_api_client.get_annual_usage_for_service(
service_id,
get_current_financial_year(),
)
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(
current_service.id,
)
usage_data = get_annual_usage_breakdown(yearly_usage, free_sms_allowance)
sms_sent = usage_data["sms_sent"]
sms_allowance_remaining = usage_data["sms_allowance_remaining"]
job_response = job_api_client.get_jobs(service_id)["data"]
service_data_retention_days = 7
@@ -89,24 +81,11 @@ def service_dashboard(service_id):
partials=get_dashboard_partials(service_id),
jobs=jobs,
service_data_retention_days=service_data_retention_days,
sms_sent=sms_sent,
sms_allowance_remaining=sms_allowance_remaining,
)
@main.route("/daily_stats.json")
def get_daily_stats():
service_id = session.get("service_id")
date_range = get_stats_date_range()
stats = service_api_client.get_service_notification_statistics_by_day(
service_id, start_date=date_range["start_date"], days=date_range["days"]
)
return jsonify(stats)
@main.route("/daily_stats_by_user.json")
def get_daily_stats_by_user():
@main.route("/services/<uuid:service_id>/daily_stats_by_user.json")
def get_daily_stats_by_user(service_id):
service_id = session.get("service_id")
date_range = get_stats_date_range()
user_id = current_user.id
@@ -360,7 +339,35 @@ def aggregate_notifications_stats(template_statistics):
return notifications
def fetch_daily_stats(service_id):
date_range = get_stats_date_range()
stats = service_api_client.get_service_notification_statistics_by_day(
service_id, start_date='2024-12-31', days=date_range["days"]
)
return stats
# Route using the helper
@main.route("/daily_stats.json")
def get_daily_stats():
service_id = session.get("service_id")
stats = fetch_daily_stats(service_id) # Use the helper
return jsonify(stats)
def get_dashboard_partials(service_id):
date_range = get_stats_date_range()
yearly_usage = billing_api_client.get_annual_usage_for_service(
service_id,
get_current_financial_year(),
)
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(
current_service.id,
)
usage_data = get_annual_usage_breakdown(yearly_usage, free_sms_allowance)
sms_sent = usage_data["sms_sent"]
sms_allowance_remaining = usage_data["sms_allowance_remaining"]
activityStats = fetch_daily_stats
all_statistics = template_statistics_client.get_template_statistics_for_service(
service_id, limit_days=7
)
@@ -384,6 +391,12 @@ def get_dashboard_partials(service_id):
get_current_financial_year(),
)
return {
"activity": render_template(
"views/dashboard/_activity.html",
activityStats=activityStats,
sms_sent=sms_sent,
sms_allowance_remaining=sms_allowance_remaining,
),
"upcoming": render_template(
"views/dashboard/_upcoming.html",
),

View File

@@ -334,6 +334,18 @@ def get_status_filters(service, message_type, statistics):
def _get_job_counts(job):
print('''
job
''', dir(job))
print(job.notifications_sending)
job_type = job.template_type
return [
(
@@ -358,7 +370,7 @@ def _get_job_counts(job):
],
[
Markup(
f"""pending<span class="usa-sr-only">
f"""pending--fdsjfisodj<span class="usa-sr-only">
{message_count_noun(job.notifications_sending, job_type)}</span>"""
),
"pending",

View File

@@ -28,7 +28,7 @@ class JobApiClient(NotifyAdminAPIClient):
def get_job(self, service_id, job_id):
params = {}
job = self.get(url=f"/service/{service_id}/job/{job_id}", params=params)
# comment
return job
def get_jobs(self, service_id, *, limit_days=None, statuses=None, page=1):

View File

@@ -2,6 +2,7 @@
{% if link %}
<a class="usa-link display-flex" href="{{ link }}">
{% endif %}
big number
<span class="big-number{% if smaller %}-smaller{% endif %}{% if smallest %}-smallest{% endif %}">
<span class="big-number-number">
{% if number is number %}

View File

@@ -8,6 +8,7 @@
) %}
<nav aria-labelledby='page-header'>
<ul class='pill'>
Pill
{% for label, option, link, count in items %}
<li class="pill-item__container">
{% if current_value == option %}

View File

@@ -2,6 +2,7 @@
<div class="ajax-block-container">
<div class="tabs">
count
{{ pill(counts, request.args.get('status', '')) }}
</div>
</div>

View File

@@ -16,7 +16,7 @@
</ul>
</div>
{% endif %}
<h2>Delivery Status</h2>
<h2>Delivery Stadsadatus</h2>
{% endset %}
<div class="ajax-block-container">

View File

@@ -25,13 +25,8 @@
<h2 class="font-body-2xl line-height-sans-2 margin-top-0">{{ current_service.name }} Dashboard</h2>
{{ ajax_block(partials, updates_url, 'inbox') }}
{{ ajax_block(partials, updates_url, 'activity') }}
<div id="totalMessageChartContainer" data-sms-sent="{{ sms_sent }}" data-sms-allowance-remaining="{{ sms_allowance_remaining }}">
<h2 id="chartTitle">Total messages</h2>
<svg id="totalMessageChart"></svg>
<div id="message"></div>
</div>
<div id="totalMessageTable" class="margin-0"></div>
<h2 class="line-height-sans-2 margin-bottom-0 margin-top-4">Recent activity</h2>
<div id="activityChartContainer">