mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-07 03:58:24 -04:00
first round
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
const COLORS = {
|
const COLORS = {
|
||||||
delivered: '#0076d6',
|
delivered: '#0076d6',
|
||||||
failed: '#fa9441',
|
failed: '#fa9441',
|
||||||
|
pending: '#808080',
|
||||||
text: '#666'
|
text: '#666'
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,7 +46,8 @@
|
|||||||
// Show legend if there are messages
|
// Show legend if there are messages
|
||||||
const legendData = [
|
const legendData = [
|
||||||
{ label: 'Delivered', color: COLORS.delivered },
|
{ 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')
|
const legendItem = legendContainer.selectAll('.legend-item')
|
||||||
@@ -100,12 +102,13 @@
|
|||||||
const stackData = labels.map((label, i) => ({
|
const stackData = labels.map((label, i) => ({
|
||||||
label: label,
|
label: label,
|
||||||
delivered: deliveredData[i],
|
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
|
// Stack the data
|
||||||
const stack = d3.stack()
|
const stack = d3.stack()
|
||||||
.keys(['delivered', 'failed'])
|
.keys(['delivered', 'failed', 'pending'])
|
||||||
.order(d3.stackOrderNone)
|
.order(d3.stackOrderNone)
|
||||||
.offset(d3.stackOffsetNone);
|
.offset(d3.stackOffsetNone);
|
||||||
|
|
||||||
@@ -113,8 +116,8 @@
|
|||||||
|
|
||||||
// Color scale
|
// Color scale
|
||||||
const color = d3.scaleOrdinal()
|
const color = d3.scaleOrdinal()
|
||||||
.domain(['delivered', 'failed'])
|
.domain(['delivered', 'failed', 'pending'])
|
||||||
.range([COLORS.delivered, COLORS.failed]);
|
.range([COLORS.delivered, COLORS.failed, COLORS.pending]);
|
||||||
|
|
||||||
// Create bars with animation
|
// Create bars with animation
|
||||||
const barGroups = svg.selectAll('.bar-group')
|
const barGroups = svg.selectAll('.bar-group')
|
||||||
@@ -164,7 +167,7 @@
|
|||||||
|
|
||||||
// Create table header
|
// Create table header
|
||||||
const headerRow = document.createElement('tr');
|
const headerRow = document.createElement('tr');
|
||||||
const headers = ['Day', 'Delivered', 'Failed'];
|
const headers = ['Day', 'Delivered', 'Failed', 'Pending'];
|
||||||
headers.forEach(headerText => {
|
headers.forEach(headerText => {
|
||||||
const th = document.createElement('th');
|
const th = document.createElement('th');
|
||||||
th.textContent = headerText;
|
th.textContent = headerText;
|
||||||
@@ -187,6 +190,10 @@
|
|||||||
cellFailed.textContent = failedData[index];
|
cellFailed.textContent = failedData[index];
|
||||||
row.appendChild(cellFailed);
|
row.appendChild(cellFailed);
|
||||||
|
|
||||||
|
const cellPending = document.createElement('td');
|
||||||
|
cellPending.textContent = pendingData[index];
|
||||||
|
row.appendChild(cellPending);
|
||||||
|
|
||||||
tbody.appendChild(row);
|
tbody.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -213,6 +220,7 @@
|
|||||||
labels = [];
|
labels = [];
|
||||||
deliveredData = [];
|
deliveredData = [];
|
||||||
failedData = [];
|
failedData = [];
|
||||||
|
pendingData = [];
|
||||||
|
|
||||||
let totalMessages = 0;
|
let totalMessages = 0;
|
||||||
|
|
||||||
@@ -224,7 +232,7 @@
|
|||||||
labels.push(formattedDate);
|
labels.push(formattedDate);
|
||||||
deliveredData.push(data[dateString].sms.delivered);
|
deliveredData.push(data[dateString].sms.delivered);
|
||||||
failedData.push(data[dateString].sms.failure);
|
failedData.push(data[dateString].sms.failure);
|
||||||
|
pendingData.push(data[dateString].sms.pending || 0);
|
||||||
// Calculate the total number of messages
|
// Calculate the total number of messages
|
||||||
totalMessages += data[dateString].sms.delivered + data[dateString].sms.failure;
|
totalMessages += data[dateString].sms.delivered + data[dateString].sms.failure;
|
||||||
}
|
}
|
||||||
@@ -260,7 +268,7 @@
|
|||||||
})
|
})
|
||||||
.catch(error => console.error('Error fetching daily stats:', error));
|
.catch(error => console.error('Error fetching daily stats:', error));
|
||||||
};
|
};
|
||||||
|
// setInterval(() => fetchData('service'), 1000);
|
||||||
const handleDropdownChange = function(event) {
|
const handleDropdownChange = function(event) {
|
||||||
const selectedValue = event.target.value;
|
const selectedValue = event.target.value;
|
||||||
const subTitle = document.querySelector(`#activityChartContainer .chart-subtitle`);
|
const subTitle = document.querySelector(`#activityChartContainer .chart-subtitle`);
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ def message_count_noun(count, template_type):
|
|||||||
|
|
||||||
|
|
||||||
def message_count(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):
|
def recipient_count_label(count, template_type):
|
||||||
|
|||||||
@@ -48,16 +48,8 @@ def service_dashboard(service_id):
|
|||||||
if not current_user.has_permissions("view_activity"):
|
if not current_user.has_permissions("view_activity"):
|
||||||
return redirect(url_for("main.choose_template", service_id=service_id))
|
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"]
|
job_response = job_api_client.get_jobs(service_id)["data"]
|
||||||
service_data_retention_days = 7
|
service_data_retention_days = 7
|
||||||
@@ -89,24 +81,11 @@ def service_dashboard(service_id):
|
|||||||
partials=get_dashboard_partials(service_id),
|
partials=get_dashboard_partials(service_id),
|
||||||
jobs=jobs,
|
jobs=jobs,
|
||||||
service_data_retention_days=service_data_retention_days,
|
service_data_retention_days=service_data_retention_days,
|
||||||
sms_sent=sms_sent,
|
|
||||||
sms_allowance_remaining=sms_allowance_remaining,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@main.route("/daily_stats.json")
|
@main.route("/services/<uuid:service_id>/daily_stats_by_user.json")
|
||||||
def get_daily_stats():
|
def get_daily_stats_by_user(service_id):
|
||||||
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():
|
|
||||||
service_id = session.get("service_id")
|
service_id = session.get("service_id")
|
||||||
date_range = get_stats_date_range()
|
date_range = get_stats_date_range()
|
||||||
user_id = current_user.id
|
user_id = current_user.id
|
||||||
@@ -360,7 +339,35 @@ def aggregate_notifications_stats(template_statistics):
|
|||||||
return notifications
|
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):
|
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(
|
all_statistics = template_statistics_client.get_template_statistics_for_service(
|
||||||
service_id, limit_days=7
|
service_id, limit_days=7
|
||||||
)
|
)
|
||||||
@@ -384,6 +391,12 @@ def get_dashboard_partials(service_id):
|
|||||||
get_current_financial_year(),
|
get_current_financial_year(),
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
|
"activity": render_template(
|
||||||
|
"views/dashboard/_activity.html",
|
||||||
|
activityStats=activityStats,
|
||||||
|
sms_sent=sms_sent,
|
||||||
|
sms_allowance_remaining=sms_allowance_remaining,
|
||||||
|
),
|
||||||
"upcoming": render_template(
|
"upcoming": render_template(
|
||||||
"views/dashboard/_upcoming.html",
|
"views/dashboard/_upcoming.html",
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -334,6 +334,18 @@ def get_status_filters(service, message_type, statistics):
|
|||||||
|
|
||||||
|
|
||||||
def _get_job_counts(job):
|
def _get_job_counts(job):
|
||||||
|
print('''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
job
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
''', dir(job))
|
||||||
|
print(job.notifications_sending)
|
||||||
|
|
||||||
job_type = job.template_type
|
job_type = job.template_type
|
||||||
return [
|
return [
|
||||||
(
|
(
|
||||||
@@ -358,7 +370,7 @@ def _get_job_counts(job):
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
Markup(
|
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>"""
|
{message_count_noun(job.notifications_sending, job_type)}</span>"""
|
||||||
),
|
),
|
||||||
"pending",
|
"pending",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class JobApiClient(NotifyAdminAPIClient):
|
|||||||
def get_job(self, service_id, job_id):
|
def get_job(self, service_id, job_id):
|
||||||
params = {}
|
params = {}
|
||||||
job = self.get(url=f"/service/{service_id}/job/{job_id}", params=params)
|
job = self.get(url=f"/service/{service_id}/job/{job_id}", params=params)
|
||||||
|
# comment
|
||||||
return job
|
return job
|
||||||
|
|
||||||
def get_jobs(self, service_id, *, limit_days=None, statuses=None, page=1):
|
def get_jobs(self, service_id, *, limit_days=None, statuses=None, page=1):
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{% if link %}
|
{% if link %}
|
||||||
<a class="usa-link display-flex" href="{{ link }}">
|
<a class="usa-link display-flex" href="{{ link }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
big number
|
||||||
<span class="big-number{% if smaller %}-smaller{% endif %}{% if smallest %}-smallest{% endif %}">
|
<span class="big-number{% if smaller %}-smaller{% endif %}{% if smallest %}-smallest{% endif %}">
|
||||||
<span class="big-number-number">
|
<span class="big-number-number">
|
||||||
{% if number is number %}
|
{% if number is number %}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
) %}
|
) %}
|
||||||
<nav aria-labelledby='page-header'>
|
<nav aria-labelledby='page-header'>
|
||||||
<ul class='pill'>
|
<ul class='pill'>
|
||||||
|
Pill
|
||||||
{% for label, option, link, count in items %}
|
{% for label, option, link, count in items %}
|
||||||
<li class="pill-item__container">
|
<li class="pill-item__container">
|
||||||
{% if current_value == option %}
|
{% if current_value == option %}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<div class="ajax-block-container">
|
<div class="ajax-block-container">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
|
count
|
||||||
{{ pill(counts, request.args.get('status', '')) }}
|
{{ pill(counts, request.args.get('status', '')) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h2>Delivery Status</h2>
|
<h2>Delivery Stadsadatus</h2>
|
||||||
{% endset %}
|
{% endset %}
|
||||||
|
|
||||||
<div class="ajax-block-container">
|
<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>
|
<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, '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>
|
<h2 class="line-height-sans-2 margin-bottom-0 margin-top-4">Recent activity</h2>
|
||||||
<div id="activityChartContainer">
|
<div id="activityChartContainer">
|
||||||
|
|||||||
Reference in New Issue
Block a user