diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 5e5cafc8c..c200e11f6 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -1,6 +1,7 @@ from datetime import datetime, date, timedelta from collections import namedtuple from itertools import groupby +import json from flask import ( render_template, @@ -48,8 +49,8 @@ def service_dashboard(service_id): return render_template( 'views/dashboard/dashboard.html', - templates=service_api_client.get_service_templates(service_id)['data'], - **get_dashboard_statistics_for_service(service_id) + updates_url=url_for(".service_dashboard_updates", service_id=service_id), + partials=get_dashboard_partials(service_id) ) @@ -57,12 +58,7 @@ def service_dashboard(service_id): @login_required @user_has_permissions('view_activity', admin_override=True) def service_dashboard_updates(service_id): - return jsonify(**{ - 'today': render_template( - 'views/dashboard/today.html', - **get_dashboard_statistics_for_service(service_id) - ) - }) + return jsonify(**get_dashboard_partials(service_id)) @main.route("/services//template-activity") @@ -87,7 +83,7 @@ def template_history(service_id): def usage(service_id): return render_template( 'views/usage.html', - **get_dashboard_statistics_for_service(service_id) + **calculate_usage(service_api_client.get_service_usage(service_id)['data']) ) @@ -143,35 +139,54 @@ def aggregate_usage(template_statistics): ) -def get_dashboard_statistics_for_service(service_id): - - usage = service_api_client.get_service_usage(service_id) - sms_free_allowance = 250000 - sms_rate = 0.018 - - sms_sent = usage['data'].get('sms_count', 0) - emails_sent = usage['data'].get('email_count', 0) +def get_dashboard_partials(service_id): template_statistics = aggregate_usage( template_statistics_client.get_template_statistics_for_service(service_id, limit_days=7) ) + jobs = add_rate_to_jobs(filter( + lambda job: job['original_file_name'] != current_app.config['TEST_MESSAGE_FILENAME'], + job_api_client.get_job(service_id, limit_days=7)['data'] + )) + return { - 'statistics': add_rates_to(sum_of_statistics( - statistics_api_client.get_statistics_for_service(service_id, limit_days=7)['data'] - )), - 'template_statistics': template_statistics, - 'most_used_template_count': max( - [row['usage_count'] for row in template_statistics] or [0] + 'totals': render_template( + 'views/dashboard/_totals.html', + statistics=add_rates_to(sum_of_statistics( + statistics_api_client.get_statistics_for_service(service_id, limit_days=7)['data'] + )) ), + 'template-statistics': render_template( + 'views/dashboard/template-statistics.html', + template_statistics=template_statistics, + most_used_template_count=max( + [row['usage_count'] for row in template_statistics] or [0] + ), + ), + 'has_template_statistics': bool(template_statistics), + 'jobs': render_template( + 'views/dashboard/_jobs.html', + jobs=jobs + ), + 'has_jobs': bool(jobs), + 'usage': render_template( + 'views/dashboard/_usage.html', + **calculate_usage(service_api_client.get_service_usage(service_id)['data']) + ), + } + + +def calculate_usage(usage, sms_free_allowance=250000, sms_rate=0.018): + + sms_sent = usage.get('sms_count', 0) + emails_sent = usage.get('email_count', 0) + + return { 'emails_sent': emails_sent, 'sms_free_allowance': sms_free_allowance, 'sms_sent': sms_sent, 'sms_allowance_remaining': max(0, (sms_free_allowance - sms_sent)), 'sms_chargeable': max(0, sms_sent - sms_free_allowance), - 'sms_rate': sms_rate, - 'jobs': add_rate_to_jobs(filter( - lambda job: job['original_file_name'] != current_app.config['TEST_MESSAGE_FILENAME'], - job_api_client.get_job(service_id, limit_days=7)['data'] - )) + 'sms_rate': sms_rate } diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index 931e03324..4d6e71a60 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -70,22 +70,13 @@ def view_jobs(service_id): @login_required @user_has_permissions('view_activity', admin_override=True) def view_job(service_id, job_id): - job = job_api_client.get_job(service_id, job_id)['data'] - template = service_api_client.get_service_template(service_id=service_id, - template_id=job['template'], - version=job['template_version'])['data'] + job = job_api_client.get_job(service_id, job_id)['data'] filter_args = _parse_filter_args(request.args) _set_status_filters(filter_args) - notifications = notification_api_client.get_notifications_for_service( - service_id, job_id, status=filter_args.get('status'), - ) - finished = job['status'] == 'finished' + return render_template( 'views/jobs/job.html', - notifications=notifications['notifications'], - job=job, - uploaded_at=job['created_at'], finished=job.get('notifications_sent', 0) and (( job.get('notifications_sent', 0) - job.get('notifications_delivered', 0) - @@ -93,11 +84,21 @@ def view_job(service_id, job_id): ) == 0), uploaded_file_name=job['original_file_name'], template=Template( - template, + service_api_client.get_service_template( + service_id=service_id, + template_id=job['template'], + version=job['template_version'] + )['data'], prefix=current_service['name'] ), - counts=_get_job_counts(job, request.args.get('help', 0)), - status=request.args.get('status', '') + status=request.args.get('status', ''), + updates_url=url_for( + ".view_job_updates", + service_id=service_id, + job_id=job['id'], + status=request.args.get('status', '') + ), + partials=get_job_partials(job) ) @@ -138,38 +139,9 @@ def view_job_csv(service_id, job_id): @login_required @user_has_permissions('view_activity', admin_override=True) def view_job_updates(service_id, job_id): - job = job_api_client.get_job(service_id, job_id)['data'] - filter_args = _parse_filter_args(request.args) - _set_status_filters(filter_args) - notifications = notification_api_client.get_notifications_for_service( - service_id, job_id, status=filter_args.get('status') - ) - finished = ( - job.get('notifications_sent', 0) - - job.get('notifications_delivered', 0) - - job.get('notifications_failed', 0) - ) == 0 - return jsonify(**{ - 'counts': render_template( - 'partials/jobs/count.html', - job=job, - finished=finished, - counts=_get_job_counts(job, request.args.get('help', 0)), - status=request.args.get('status', '') - ), - 'notifications': render_template( - 'partials/jobs/notifications.html', - job=job, - notifications=notifications['notifications'], - finished=finished, - status=request.args.get('status', '') - ), - 'status': render_template( - 'partials/jobs/status.html', - job=job, - finished=finished - ), - }) + return jsonify(**get_job_partials( + job_api_client.get_job(service_id, job_id)['data'] + )) @main.route('/services//notifications/') @@ -319,3 +291,30 @@ def _get_job_counts(job, help_argument): ] ] ] + + +def get_job_partials(job): + + filter_args = _parse_filter_args(request.args) + _set_status_filters(filter_args) + + return { + 'counts': render_template( + 'partials/jobs/count.html', + job=job, + counts=_get_job_counts(job, request.args.get('help', 0)), + status=request.args.get('status', '') + ), + 'notifications': render_template( + 'partials/jobs/notifications.html', + job=job, + notifications=notification_api_client.get_notifications_for_service( + job['service'], job['id'], status=filter_args.get('status') + )['notifications'], + status=request.args.get('status', '') + ), + 'status': render_template( + 'partials/jobs/status.html', + job=job + ), + } diff --git a/app/templates/components/ajax-block.html b/app/templates/components/ajax-block.html new file mode 100644 index 000000000..4382bf700 --- /dev/null +++ b/app/templates/components/ajax-block.html @@ -0,0 +1,15 @@ +{% macro ajax_block(partials, url, key, interval=2, finished=False) %} + {% if not finished %} +
+ {% endif %} + {{ partials[key]|safe }} + {% if not finished %} +
+ {% endif %} +{% endmacro %} diff --git a/app/templates/partials/jobs/count.html b/app/templates/partials/jobs/count.html index a1ad9a0af..a9f91e093 100644 --- a/app/templates/partials/jobs/count.html +++ b/app/templates/partials/jobs/count.html @@ -1,16 +1,5 @@ {% from "components/pill.html" import pill %} -
- -
- {{ pill('Status', counts, status) }} -
- +
+ {{ pill('Status', counts, status) }}
diff --git a/app/templates/partials/jobs/notifications.html b/app/templates/partials/jobs/notifications.html index c045d7bae..0ba32b741 100644 --- a/app/templates/partials/jobs/notifications.html +++ b/app/templates/partials/jobs/notifications.html @@ -1,16 +1,8 @@ {% from "components/table.html" import list_table, field, right_aligned_field_heading, date_field, row_heading %} -
+{% if notifications %} +
+{% endif %} {% if notifications %}

@@ -46,4 +38,6 @@ {% endcall %} {% endcall %} -

+{% if notifications %} +
+{% endif %} diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index ec4f0a308..6c46bbaf2 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -1,11 +1,4 @@ -
+

Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }}

diff --git a/app/templates/views/dashboard/_jobs.html b/app/templates/views/dashboard/_jobs.html index 79b523a7b..b414e4456 100644 --- a/app/templates/views/dashboard/_jobs.html +++ b/app/templates/views/dashboard/_jobs.html @@ -1,12 +1,12 @@ {% from "components/table.html" import list_table, field, right_aligned_field_heading, row_heading %} -{% from "components/big-number.html" import big_number %} +{% from "components/big-number.html" import big_number -%}
{% call(item, row_number) list_table( jobs, - caption="Recent batch jobs", + caption="Recent files uploaded", caption_visible=False, - empty_message='You haven’t sent any batch messages yet', + empty_message='You haven’t uploaded any files recently', field_headings=[ 'File', 'Sending', diff --git a/app/templates/views/dashboard/_totals.html b/app/templates/views/dashboard/_totals.html new file mode 100644 index 000000000..213f73c93 --- /dev/null +++ b/app/templates/views/dashboard/_totals.html @@ -0,0 +1,27 @@ +{% from "components/big-number.html" import big_number_with_status %} +{% from "components/message-count-label.html" import message_count_label %} + +
+
+ {{ big_number_with_status( + statistics.emails_requested, + message_count_label(statistics.emails_requested, 'email', suffix=''), + statistics.emails_failed, + statistics.get('emails_failure_rate', 0.0), + statistics.get('emails_failure_rate', 0)|float > 3, + failure_link=url_for(".view_notifications", service_id=current_service.id, message_type='email', status='failed'), + link=url_for(".view_notifications", service_id=current_service.id, message_type='email', status='sending,delivered,failed') + ) }} +
+
+ {{ big_number_with_status( + statistics.sms_requested, + message_count_label(statistics.sms_requested, 'sms', suffix=''), + statistics.sms_failed, + statistics.get('sms_failure_rate', 0.0), + statistics.get('sms_failure_rate', 0)|float > 3, + failure_link=url_for(".view_notifications", service_id=current_service.id, message_type='sms', status='failed'), + link=url_for(".view_notifications", service_id=current_service.id, message_type='sms', status='sending,delivered,failed') + ) }} +
+
diff --git a/app/templates/views/dashboard/_usage.html b/app/templates/views/dashboard/_usage.html new file mode 100644 index 000000000..066dae104 --- /dev/null +++ b/app/templates/views/dashboard/_usage.html @@ -0,0 +1,23 @@ +{% from "components/big-number.html" import big_number %} + +
+
+
+ {{ big_number("Unlimited", 'free email allowance', smaller=True) }} +
+
+
+
+ {% if sms_chargeable %} + {{ big_number( + (sms_chargeable * sms_rate), + 'spent on text messages', + currency="£", + smaller=True + ) }} + {% else %} + {{ big_number(sms_allowance_remaining, 'free text messages left', smaller=True) }} + {% endif %} +
+
+
diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index ea5e6433e..d51f3c364 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -1,5 +1,11 @@ {% extends "withnav_template.html" %} +{% from "components/big-number.html" import big_number, big_number_with_status %} +{% from "components/show-more.html" import show_more %} +{% from "components/message-count-label.html" import message_count_label %} +{% from "components/table.html" import list_table, field, right_aligned_field_heading, hidden_field_heading %} +{% from "components/ajax-block.html" import ajax_block %} + {% block page_title %} {{ current_service.name }} – GOV.UK Notify {% endblock %} @@ -21,7 +27,37 @@

In the last 7 days

- {% include 'views/dashboard/today.html' %} + + {{ ajax_block(partials, updates_url, 'totals') }} + {{ show_more( + url_for('.weekly', service_id=current_service.id), + 'Compare to previous weeks' + ) }} + + {% if partials['has_template_statistics'] %} + {{ ajax_block(partials, updates_url, 'template-statistics') }} + {{ show_more( + url_for('.template_history', service_id=current_service.id), + 'See all templates used this year' + ) }} + {% endif %} + + {% if partials['has_jobs'] %} + {{ ajax_block(partials, updates_url, 'jobs') }} + {{ show_more( + url_for('.view_jobs', service_id=current_service.id), + 'See all uploaded files' + ) }} + {% endif %} + + {% if current_user.has_permissions(['manage_settings'], admin_override=True) %} +

This year

+ {{ ajax_block(partials, updates_url, 'usage') }} + {{ show_more( + url_for(".usage", service_id=current_service['id']), + 'See usage breakdown' + ) }} + {% endif %}
diff --git a/app/templates/views/dashboard/jobs.html b/app/templates/views/dashboard/jobs.html deleted file mode 100644 index f06ce67aa..000000000 --- a/app/templates/views/dashboard/jobs.html +++ /dev/null @@ -1,26 +0,0 @@ -{% from "components/table.html" import list_table, field, right_aligned_field_heading, hidden_field_heading %} - -{% call(item, row_number) list_table( - jobs, - caption="Recent batch jobs", - empty_message='You haven’t sent any batch messages yet', - field_headings=['File', 'Started', right_aligned_field_heading('Rows')] -) %} - {% call field() %} - {{ item.original_file_name }} - {{ item.created_at|format_datetime }} - {% endcall %} - {% call field() %} - - {% endcall %} - {% call field(align='right') %} - {{ item.notification_count }} - {% endcall %} -{% endcall %} -{% if more_jobs_to_show %} - {% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %} - - {% endif %} -{% endif %} diff --git a/app/templates/views/dashboard/today.html b/app/templates/views/dashboard/today.html deleted file mode 100644 index 409c4e58a..000000000 --- a/app/templates/views/dashboard/today.html +++ /dev/null @@ -1,90 +0,0 @@ -{% from "components/big-number.html" import big_number, big_number_with_status %} -{% from "components/show-more.html" import show_more %} -{% from "components/message-count-label.html" import message_count_label %} -{% from "components/table.html" import list_table, field, right_aligned_field_heading, hidden_field_heading %} - -
-
-
- {{ big_number_with_status( - statistics.emails_requested, - message_count_label(statistics.emails_requested, 'email', suffix=''), - statistics.emails_failed, - statistics.get('emails_failure_rate', 0.0), - statistics.get('emails_failure_rate', 0)|float > 3, - failure_link=url_for(".view_notifications", service_id=current_service.id, message_type='email', status='failed'), - link=url_for(".view_notifications", service_id=current_service.id, message_type='email', status='sending,delivered,failed') - ) }} -
-
- {{ big_number_with_status( - statistics.sms_requested, - message_count_label(statistics.sms_requested, 'sms', suffix=''), - statistics.sms_failed, - statistics.get('sms_failure_rate', 0.0), - statistics.get('sms_failure_rate', 0)|float > 3, - failure_link=url_for(".view_notifications", service_id=current_service.id, message_type='sms', status='failed'), - link=url_for(".view_notifications", service_id=current_service.id, message_type='sms', status='sending,delivered,failed') - ) }} -
-
- {{ show_more( - url_for('.weekly', service_id=current_service.id), - 'Compare to previous weeks' - ) }} -
-
- - {% if template_statistics|length %} - {% include 'views/dashboard/template-statistics.html' %} - {{ show_more( - url_for('.template_history', service_id=current_service.id), - 'See all templates used this year' - ) }} - {% endif %} - - {% if jobs %} - {% include 'views/dashboard/_jobs.html' %} - {{ show_more( - url_for('.view_jobs', service_id=current_service.id), - 'See all uploaded files' - ) }} - {% endif %} - - {% if current_user.has_permissions(['manage_settings'], admin_override=True) %} -

This year

- -
-
-
- {{ big_number("Unlimited", 'free email allowance', smaller=True) }} -
-
-
-
- {% if sms_chargeable %} - {{ big_number( - (sms_chargeable * sms_rate), - 'spent on text messages', - currency="£", - smaller=True - ) }} - {% else %} - {{ big_number(sms_allowance_remaining, 'free text messages left', smaller=True) }} - {% endif %} -
-
-
- {{ show_more( - url_for(".usage", service_id=current_service['id']), - 'See usage breakdown' - ) }} - {% endif %} - -
diff --git a/app/templates/views/jobs/job.html b/app/templates/views/jobs/job.html index 17059f702..061580509 100644 --- a/app/templates/views/jobs/job.html +++ b/app/templates/views/jobs/job.html @@ -2,6 +2,7 @@ {% from "components/banner.html" import banner %} {% from "components/sms-message.html" import sms_message %} {% from "components/email-message.html" import email_message %} +{% from "components/ajax-block.html" import ajax_block %} {% block page_title %} {{ uploaded_file_name }} – GOV.UK Notify @@ -28,10 +29,8 @@ )}} {% endif %} - {% include 'partials/jobs/status.html' %} - - {% include 'partials/jobs/count.html' %} - - {% include 'partials/jobs/notifications.html' %} + {{ ajax_block(partials, updates_url, 'status', finished=finished) }} + {{ ajax_block(partials, updates_url, 'counts', finished=finished) }} + {{ ajax_block(partials, updates_url, 'notifications', finished=finished) }} {% endblock %}