mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-27 09:29:22 -04:00
first round
This commit is contained in:
@@ -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`);
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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",
|
||||
),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<div class="ajax-block-container">
|
||||
<div class="tabs">
|
||||
count
|
||||
{{ pill(counts, request.args.get('status', '')) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h2>Delivery Status</h2>
|
||||
<h2>Delivery Stadsadatus</h2>
|
||||
{% endset %}
|
||||
|
||||
<div class="ajax-block-container">
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user