diff --git a/app/assets/stylesheets/components/big-number.scss b/app/assets/stylesheets/components/big-number.scss
index f3a97af4a..3e785dcb6 100644
--- a/app/assets/stylesheets/components/big-number.scss
+++ b/app/assets/stylesheets/components/big-number.scss
@@ -21,7 +21,7 @@
@extend %big-number;
.big-number-number {
- @include bold-36($tabular-numbers: true);
+ @include bold-36();
}
}
@@ -39,31 +39,13 @@
.big-number-with-status {
@extend %big-number;
- background: $text-colour;
- color: $white;
position: relative;
margin-bottom: $gutter-half;
.big-number {
- padding: 15px;
+ padding: $gutter-half;
position: relative;
-
- }
-
- .big-number-overlay-link {
-
- background: transparent;
- position: absolute;
- top: 0;
- left: 0;
- background: transparent;
- width: 100%;
- height: 100%;
-
- &:hover {
- background: rgba($text-colour, 0.2);
- }
-
+ cursor: pointer;
}
.big-number-label {
@@ -72,9 +54,31 @@
&:link,
&:visited {
- color: $white;
- text-decoration: none;
- border-bottom: 1px solid $white;
+ color: $link-colour;
+ }
+
+ }
+
+ .big-number-link {
+
+ text-decoration: none;
+ background: $link-colour;
+ color: $white;
+ display: block;
+ border: 2px solid $link-colour;
+ margin-bottom: 5px;
+
+ &:hover {
+ color: $light-blue-25;
+ }
+
+ &:active,
+ &:focus {
+ outline: 3px solid $yellow;
+ }
+
+ .big-number-label {
+ text-decoration: underline;
}
}
@@ -85,6 +89,7 @@
@include core-19;
display: block;
background: $green;
+ color: $white;
padding: 15px;
a {
@@ -94,8 +99,13 @@
&:active,
&:hover {
color: $white;
- text-decoration: none;
- border-bottom: 1px solid $white;
+ text-decoration: underline;
+ }
+
+ &:active,
+ &:focus {
+ color: $black;
+ border-bottom: 1px solid $black;
}
}
diff --git a/app/assets/stylesheets/components/pill.scss b/app/assets/stylesheets/components/pill.scss
index de839a37c..5d3b57ce5 100644
--- a/app/assets/stylesheets/components/pill.scss
+++ b/app/assets/stylesheets/components/pill.scss
@@ -5,9 +5,9 @@
a,
span {
display: block;
- padding: 10px;
+ padding: 10px;
flex-grow: 1;
- text-align: center;
+ text-align: left;
&:first-child {
margin-left: 0;
@@ -20,13 +20,25 @@
}
a {
- background: $panel-colour;
- color: $link-colour;
- border: 1px solid $panel-colour;
+ $background: $link-colour;
+ background: $background;
+ color: $white;
+ border: 2px solid $background;
position: relative;
+ text-decoration: none;
+ cursor: pointer;
+
+ .pill-label {
+ text-decoration: underline;
+ }
+
+ &:link,
+ &:visited {
+ color: $white;
+ }
&:hover {
- color: $text-colour;
+ color: $light-blue-25;
}
&:active,
@@ -36,7 +48,10 @@
}
span {
- border: 1px solid $grey-1;
+ border: 2px solid $black;
+ outline: 1px solid rgba($white, 0.1);
+ position: relative;
+ z-index: 1000;
color: $text-colour;
}
}
diff --git a/app/assets/stylesheets/views/dashboard.scss b/app/assets/stylesheets/views/dashboard.scss
index 6069a8f20..946b78576 100644
--- a/app/assets/stylesheets/views/dashboard.scss
+++ b/app/assets/stylesheets/views/dashboard.scss
@@ -2,7 +2,7 @@
table {
th {
- @include core-16;
+ @include core-19;
border-bottom: 0;
}
@@ -26,16 +26,16 @@
width: 100%;
margin-bottom: $gutter-half;
height: $gutter-half;
- color: $govuk-blue;
+ color: $text-colour;
span {
box-sizing: border-box;
- display: block;
- background: $govuk-blue;
- color: $white;
- height: $gutter-half;
- padding-left: 5px;
- padding-right: 5px;
+ display: inline-block;
+ overflow: visible;
+ background: $panel-colour;
+ color: $black;
+ padding: 5px 5px 2px 5px;
+ text-indent: -2px;
margin: 3px 0 5px 0;
transition: width 0.6s ease-in-out;
}
@@ -49,7 +49,7 @@
color: $govuk-blue;
max-width: 100%;
background: $white;
- margin-bottom: $gutter;
+ margin-bottom: $gutter-two-thirds;
}
}
diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py
index 194cb0563..6bbcb7b5d 100644
--- a/app/main/views/jobs.py
+++ b/app/main/views/jobs.py
@@ -18,6 +18,7 @@ from app import (
job_api_client,
notification_api_client,
service_api_client,
+ statistics_api_client,
current_service,
format_datetime_short)
from app.main import main
@@ -26,6 +27,7 @@ from app.utils import (
generate_previous_next_dict,
user_has_permissions,
generate_notifications_csv)
+from app.statistics_utils import sum_of_statistics, statistics_by_state
def _parse_filter_args(filter_dict):
@@ -46,7 +48,7 @@ def _set_status_filters(filter_args):
all_failure_statuses = ['failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
all_statuses = ['sending', 'delivered'] + all_failure_statuses
if filter_args.get('status'):
- if 'processed' in filter_args.get('status'):
+ if 'processed' in filter_args.get('status') or not filter_args.get('status'):
filter_args['status'] = all_statuses
elif 'failed' in filter_args.get('status'):
filter_args['status'].extend(all_failure_statuses[1:])
@@ -73,7 +75,12 @@ def view_job(service_id, job_id):
template = service_api_client.get_service_template(service_id=service_id,
template_id=job['template'],
version=job['template_version'])['data']
- notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
+
+ 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',
@@ -93,7 +100,9 @@ def view_job(service_id, job_id):
template=Template(
template,
prefix=current_service['name']
- )
+ ),
+ counts=_get_job_counts(job, request.args.get('help', 0)),
+ status=request.args.get('status', '')
)
@@ -107,12 +116,15 @@ def view_job_csv(service_id, job_id):
template_id=job['template'],
version=job['template_version']
)['data']
+ filter_args = _parse_filter_args(request.args)
+ _set_status_filters(filter_args)
return (
generate_notifications_csv(
notification_api_client.get_notifications_for_service(
service_id,
job_id,
+ status=filter_args.get('status'),
page_size=job['notification_count']
)['notifications']
),
@@ -132,7 +144,11 @@ def view_job_csv(service_id, job_id):
@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']
- notifications = notification_api_client.get_notifications_for_service(service_id, job_id)
+ 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) -
@@ -142,13 +158,16 @@ def view_job_updates(service_id, job_id):
'counts': render_template(
'partials/jobs/count.html',
job=job,
- finished=finished
+ 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
+ finished=finished,
+ status=request.args.get('status', '')
),
'status': render_template(
'partials/jobs/status.html',
@@ -179,6 +198,9 @@ def view_notifications(service_id, message_type):
template_type=[message_type],
status=filter_args.get('status'),
limit_days=current_app.config['ACTIVITY_STATS_LIMIT_DAYS'])
+ service_statistics_by_state = statistics_by_state(sum_of_statistics(
+ statistics_api_client.get_statistics_for_service(service_id, limit_days=7)['data']
+ ))
view_dict = dict(
message_type=message_type,
status=request.args.get('status')
@@ -229,16 +251,20 @@ def view_notifications(service_id, message_type):
status=request.args.get('status')
),
status_filters=[
- [item[0], item[1], url_for(
- '.view_notifications',
- service_id=current_service['id'],
- message_type=message_type,
- status=item[1]
- )] for item in [
- ['Processed', 'sending,delivered,failed'],
- ['Sending', 'sending'],
- ['Delivered', 'delivered'],
- ['Failed', 'failed'],
+ [
+ item[0], item[1],
+ url_for(
+ '.view_notifications',
+ service_id=current_service['id'],
+ message_type=message_type,
+ status=item[1]
+ ),
+ service_statistics_by_state[message_type][item[0]]
+ ] for item in [
+ ['processed', 'sending,delivered,failed'],
+ ['sending', 'sending'],
+ ['delivered', 'delivered'],
+ ['failed', 'failed'],
]
]
)
@@ -260,3 +286,41 @@ def view_notification(service_id, job_id, notification_id):
uploaded_at=now,
job_id=job_id
)
+
+
+def _get_job_counts(job, help_argument):
+ return [
+ (
+ label,
+ query_param,
+ url_for(
+ ".view_job",
+ service_id=job['service'],
+ job_id=job['id'],
+ status=query_param,
+ help=help_argument
+ ),
+ count
+ ) for label, query_param, count in [
+ [
+ 'Processed', '',
+ job.get('notifications_sent', 0)
+ ],
+ [
+ 'Sending', 'sending',
+ (
+ job.get('notifications_sent', 0) -
+ job.get('notifications_delivered', 0) -
+ job.get('notifications_failed', 0)
+ )
+ ],
+ [
+ 'Delivered', 'delivered',
+ job.get('notifications_delivered', 0)
+ ],
+ [
+ 'Failed', 'failed',
+ job.get('notifications_failed')
+ ]
+ ]
+ ]
diff --git a/app/notify_client/job_api_client.py b/app/notify_client/job_api_client.py
index 77d0d1b01..c3d45c5f5 100644
--- a/app/notify_client/job_api_client.py
+++ b/app/notify_client/job_api_client.py
@@ -14,9 +14,12 @@ class JobApiClient(BaseAPIClient):
self.client_id = app.config['ADMIN_CLIENT_USER_NAME']
self.secret = app.config['ADMIN_CLIENT_SECRET']
- def get_job(self, service_id, job_id=None, limit_days=None):
+ def get_job(self, service_id, job_id=None, limit_days=None, status=None):
if job_id:
- return self.get(url='/service/{}/job/{}'.format(service_id, job_id))
+ params = {}
+ if status is not None:
+ params['status'] = status
+ return self.get(url='/service/{}/job/{}'.format(service_id, job_id), params=params)
params = {}
if limit_days is not None:
params['limit_days'] = limit_days
diff --git a/app/statistics_utils.py b/app/statistics_utils.py
index 604b76f1d..eca91fb83 100644
--- a/app/statistics_utils.py
+++ b/app/statistics_utils.py
@@ -48,3 +48,24 @@ def add_rates_to(delivery_statistics):
),
**delivery_statistics
)
+
+
+def statistics_by_state(statistics):
+ return {
+ 'sms': {
+ 'processed': statistics['sms_requested'],
+ 'sending': (
+ statistics['sms_requested'] - statistics['sms_failed'] - statistics['sms_delivered']
+ ),
+ 'delivered': statistics['sms_delivered'],
+ 'failed': statistics['sms_failed']
+ },
+ 'email': {
+ 'processed': statistics['emails_requested'],
+ 'sending': (
+ statistics['emails_requested'] - statistics['emails_failed'] - statistics['emails_delivered']
+ ),
+ 'delivered': statistics['emails_delivered'],
+ 'failed': statistics['emails_failed']
+ }
+ }
diff --git a/app/templates/components/big-number.html b/app/templates/components/big-number.html
index 062297855..33996580d 100644
--- a/app/templates/components/big-number.html
+++ b/app/templates/components/big-number.html
@@ -1,4 +1,7 @@
-{% macro big_number(number, label, label_link=None, currency='', smaller=False, smallest=False) %}
+{% macro big_number(number, label, link=None, currency='', smaller=False, smallest=False) %}
+ {% if link %}
+
+ {% endif %}
+ Download as a CSV file + + Delivery information is available for 7 days +
+ {% endif %} + {% call(item, row_number) list_table( notifications, caption=uploaded_file_name, caption_visible=False, - empty_message="No messages to show yet", + empty_message="No messages to show", field_headings=[ 'Recipient', 'Time', diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 2ef0016c7..ec4f0a308 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -1,12 +1,12 @@+
Uploaded by {{ job.created_by.name }} on {{ job.created_at|format_datetime_short }}