diff --git a/app/__init__.py b/app/__init__.py
index 643a9cd02..2f86e12d4 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -202,7 +202,7 @@ def format_datetime_normal(date):
def format_datetime_short(date):
- return gmt_timezones(date).strftime('%d %B at %H:%M')
+ return gmt_timezones(date).strftime('%d %B at %H:%M').lstrip('0')
def format_time(date):
diff --git a/app/assets/stylesheets/views/dashboard.scss b/app/assets/stylesheets/views/dashboard.scss
index a2697f7b3..1f4d2022e 100644
--- a/app/assets/stylesheets/views/dashboard.scss
+++ b/app/assets/stylesheets/views/dashboard.scss
@@ -1,6 +1,16 @@
.dashboard {
- table th {
- font-size: 0;
+
+ table {
+ th {
+ @include core-16;
+ padding-top: 0;
+ border: 0;
+ }
+
+ td {
+ @include core-19;
+ border: 0;
+ }
}
}
@@ -15,12 +25,9 @@
box-sizing: border-box;
display: block;
width: 100%;
- text-align: right;
margin-bottom: $gutter-half;
height: $gutter-half;
color: $govuk-blue;
- text-align: left;
- color: $govuk-blue;
span {
box-sizing: border-box;
@@ -47,3 +54,17 @@
}
}
+
+.file-list {
+
+ &-filename {
+ @include bold-19;
+ }
+
+ &-hint {
+ @include core-16;
+ display: block;
+ color: $secondary-text-colour;
+ }
+
+}
diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py
index 685d5d400..2ef455e9a 100644
--- a/app/main/views/dashboard.py
+++ b/app/main/views/dashboard.py
@@ -16,6 +16,7 @@ from flask_login import login_required
from app.main import main
from app import (
+ job_api_client,
statistics_api_client,
service_api_client,
template_statistics_client
@@ -217,4 +218,5 @@ def get_dashboard_statistics_for_service(service_id):
'sms_allowance_remaining': max(0, (sms_free_allowance - sms_sent)),
'sms_chargeable': max(0, sms_sent - sms_free_allowance),
'sms_rate': sms_rate,
+ 'jobs': job_api_client.get_job(service_id, limit_days=7)['data']
}
diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py
index 7ac4cbe2e..108281368 100644
--- a/app/main/views/jobs.py
+++ b/app/main/views/jobs.py
@@ -90,12 +90,13 @@ def view_job(service_id, job_id):
return render_template(
'views/jobs/job.html',
notifications=notifications['notifications'],
- counts={
- 'queued': 0 if finished else job['notification_count'],
- 'sent': job['notification_count'] if finished else 0
- },
+ job=job,
uploaded_at=job['created_at'],
- finished_at=job['updated_at'] if finished else None,
+ finished=job.get('notifications_sent', 0) and ((
+ job.get('notifications_sent', 0) -
+ job.get('notifications_delivered', 0) -
+ job.get('notifications_failed', 0)
+ ) == 0),
uploaded_file_name=job['original_file_name'],
first_email_template=[
template for template in service_api_client.get_service_templates(service_id)['data']
@@ -104,9 +105,7 @@ def view_job(service_id, job_id):
template=Template(
template,
prefix=current_service['name']
- ),
- job_id=job_id,
- created_by=job['created_by']['name']
+ )
)
@@ -116,24 +115,27 @@ def view_job(service_id, job_id):
def view_job_updates(service_id, job_id):
job = job_api_client.get_job(service_id, job_id)['data']
notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
- finished = job['status'] == 'finished'
+ 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',
- counts={
- 'queued': 0 if finished else job['notification_count'],
- 'sent': job['notification_count'] if finished else 0
- }
+ job=job,
+ finished=finished
),
'notifications': render_template(
'partials/jobs/notifications.html',
- notifications=notifications['notifications']
+ job=job,
+ notifications=notifications['notifications'],
+ finished=finished
),
'status': render_template(
'partials/jobs/status.html',
- uploaded_at=job['created_at'],
- finished_at=job['updated_at'] if finished else None,
- created_by=job['created_by']['name']
+ job=job,
+ finished=finished
),
})
diff --git a/app/templates/components/big-number.html b/app/templates/components/big-number.html
index b52f98c6f..3a2991b0f 100644
--- a/app/templates/components/big-number.html
+++ b/app/templates/components/big-number.html
@@ -14,7 +14,7 @@
{% if label_link %}
{{ label }}
- {% else %}
+ {% elif label %}
{{ label }}
{% endif %}
diff --git a/app/templates/partials/jobs/count.html b/app/templates/partials/jobs/count.html
index 78583a7f6..38ea4e5e7 100644
--- a/app/templates/partials/jobs/count.html
+++ b/app/templates/partials/jobs/count.html
@@ -1,9 +1,9 @@
{% from "components/big-number.html" import big_number %}
{{ big_number(
- counts.queued, 'queued'
+ job.get('notifications_sent', 0) - job.get('notifications_delivered', 0) - job.get('notifications_failed', 0), 'sending'
)}}
{{ big_number(
- counts.sent, 'processed'
+ job.get('notifications_delivered', 0), 'delivered'
+ )}}
+
+
+ {{ big_number(
+ job.notifications_failed, 'failed'
)}}
diff --git a/app/templates/partials/jobs/notifications.html b/app/templates/partials/jobs/notifications.html
index 4c0159efa..0bbdd2b46 100644
--- a/app/templates/partials/jobs/notifications.html
+++ b/app/templates/partials/jobs/notifications.html
@@ -1,9 +1,9 @@
{% from "components/table.html" import list_table, field, right_aligned_field_heading %}
- Sent by {{ created_by }} on {{ uploaded_at|format_datetime_short }}
+ 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
new file mode 100644
index 000000000..26dc0acca
--- /dev/null
+++ b/app/templates/views/dashboard/_jobs.html
@@ -0,0 +1,35 @@
+{% from "components/table.html" import list_table, field, right_aligned_field_heading %}
+{% from "components/big-number.html" import big_number %}
+
+{% call(item, row_number) list_table(
+ jobs,
+ caption="Recent batch jobs",
+ caption_visible=False,
+ empty_message='You haven’t sent any batch messages yet',
+ field_headings=[
+ 'File',
+ right_aligned_field_heading('Sending'),
+ right_aligned_field_heading('Delivered'),
+ right_aligned_field_heading('Failed')
+ ],
+ field_headings_visible=True
+) %}
+ {% call field() %}
+
{{ item.original_file_name }}
+ {{ item.created_at|format_datetime }}
{% endcall %}
{% call field() %}
- {{ item.created_at|format_datetime }}
+
{% endcall %}
{% call field(align='right') %}
{{ item.notification_count }}
diff --git a/app/templates/views/dashboard/today.html b/app/templates/views/dashboard/today.html
index b3058951e..1b34d6e76 100644
--- a/app/templates/views/dashboard/today.html
+++ b/app/templates/views/dashboard/today.html
@@ -1,6 +1,7 @@
{% 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 %}
-
+
{% if template_statistics|length %}
{% include 'views/dashboard/template-statistics.html' %}
{{ show_more(
@@ -48,8 +49,16 @@
) }}
{% 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
+
This year
diff --git a/app/templates/views/jobs/jobs.html b/app/templates/views/jobs/jobs.html
index 58c26038a..7745a241b 100644
--- a/app/templates/views/jobs/jobs.html
+++ b/app/templates/views/jobs/jobs.html
@@ -1,44 +1,12 @@
{% extends "withnav_template.html" %}
-{% from "components/table.html" import list_table, field, right_aligned_field_heading %}
{% block page_title %}
Notifications activity – GOV.UK Notify
{% endblock %}
{% block maincolumn_content %}
-
-
Notifications activity
-
- All messages
-
-
- Text messages
- Email messages
-
-
- Successful messages
- Failed messages
-
- {% call(item, row_number) list_table(
- jobs,
- caption="Recent activity",
- caption_visible=False,
- empty_message='You haven’t sent any notifications yet',
- field_headings=['Job', 'Time', 'Uploaded by', right_aligned_field_heading('Status')]
- ) %}
- {% call field() %}
-
{{ item.original_file_name }}
- {% endcall %}
- {% call field() %}
- {{ item.created_at | format_datetime}}
- {% endcall %}
- {% call field() %}
- {{ item.created_by.name }}
- {% endcall %}
- {% call field(align='right') %}
- {{ item.status }}
- {% endcall %}
- {% endcall %}
-
-
+
Uploaded files
+
+ {% include 'views/dashboard/_jobs.html' %}
+
{% endblock %}
diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py
index 3326d0f92..3e5b1268e 100644
--- a/tests/app/main/views/test_jobs.py
+++ b/tests/app/main/views/test_jobs.py
@@ -20,7 +20,7 @@ def test_should_return_list_of_all_jobs(app_,
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
- assert page.h1.string == 'Notifications activity'
+ assert page.h1.string == 'Uploaded files'
jobs = page.tbody.find_all('tr')
assert len(jobs) == 5
@@ -49,6 +49,7 @@ def test_should_show_page_for_one_job(
assert "Delivered at 11:10" in content
+@freeze_time("2016-01-01 11:09:00.061258")
def test_should_show_updates_for_one_job_as_json(
app_,
service_one,
@@ -66,12 +67,15 @@ def test_should_show_updates_for_one_job_as_json(
assert response.status_code == 200
content = json.loads(response.get_data(as_text=True))
- assert 'processed' in content['counts']
- assert 'queued' in content['counts']
+ assert 'sending' in content['counts']
+ assert 'delivered' in content['counts']
+ assert 'failed' in content['counts']
assert 'Recipient' in content['notifications']
+ assert '07123456789' in content['notifications']
assert 'Status' in content['notifications']
- assert 'Sent by Test User' in content['status']
assert job_json['status'] in content['status']
+ assert 'Delivered at 11:10' in content['notifications']
+ assert 'Uploaded by Test User on 1 January at 11:09' in content['status']
def test_should_show_notifications_for_a_service(app_,
@@ -90,7 +94,7 @@ def test_should_show_notifications_for_a_service(app_,
assert notification['to'] in content
assert notification['status'] in content
assert notification['template']['name'] in content
- assert 'Download as a CSV file' in content
+ assert 'csv' in content
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Activity'
@@ -118,7 +122,7 @@ def test_can_view_only_sms_notifications_for_a_service(app_,
assert notification['to'] in content
assert notification['status'] in content
assert notification['template']['name'] in content
- assert 'Download as a CSV file' in content
+ assert 'csv' in content
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Text messages'
@@ -146,7 +150,7 @@ def test_can_view_only_email_notifications_for_a_service(app_,
assert notification['to'] in content
assert notification['status'] in content
assert notification['template']['name'] in content
- assert 'Download as a CSV file' in content
+ assert 'csv' in content
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Emails'
@@ -172,7 +176,7 @@ def test_can_view_successful_notifications_for_a_service(app_,
assert notification['to'] in content
assert notification['status'] in content
assert notification['template']['name'] in content
- assert 'Download as a CSV file' in content
+ assert 'csv' in content
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Successful emails and text messages'
@@ -198,7 +202,7 @@ def test_can_view_failed_notifications_for_a_service(app_,
assert notification['to'] in content
assert notification['status'] in content
assert notification['template']['name'] in content
- assert 'Download as a CSV file' in content
+ assert 'csv' in content
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Failed emails and text messages'
@@ -264,30 +268,6 @@ def test_should_download_notifications_for_a_service(app_,
assert 'text/csv' in response.headers['Content-Type']
-def test_should_download_api_notifications_for_a_service(app_,
- api_user_active,
- mock_login,
- mock_get_service,
- mock_get_job,
- mock_get_notifications,
- mock_get_template_version,
- mock_has_permissions,
- fake_uuid):
- with app_.test_request_context():
- with app_.test_client() as client:
- client.login(api_user_active)
- response = client.get(url_for(
- 'main.view_notifications',
- service_id=fake_uuid,
- download='csv'))
- notifications = mock_get_notifications(fake_uuid)['notifications']
- assert all([x['job'] is None for x in notifications])
- csv_content = generate_notifications_csv(notifications)
- assert response.status_code == 200
- assert response.get_data(as_text=True) == csv_content
- assert 'text/csv' in response.headers['Content-Type']
-
-
@freeze_time("2016-01-01 11:09:00.061258")
def test_should_download_notifications_for_a_job(app_,
api_user_active,
@@ -311,4 +291,4 @@ def test_should_download_notifications_for_a_job(app_,
assert response.status_code == 200
assert response.get_data(as_text=True) == csv_content
assert 'text/csv' in response.headers['Content-Type']
- assert 'sample template - 01 January at 11:09.csv"' in response.headers['Content-Disposition']
+ assert 'sample template - 1 January at 11:09.csv"' in response.headers['Content-Disposition']
diff --git a/tests/conftest.py b/tests/conftest.py
index 037f3814b..db0061da7 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -794,7 +794,7 @@ def mock_get_job(mocker, api_user_active):
@pytest.fixture(scope='function')
def mock_get_jobs(mocker, api_user_active):
- def _get_jobs(service_id):
+ def _get_jobs(service_id, limit_days=None):
data = []
for i in range(5):
job_data = job_json(service_id, api_user_active)