mirror of
https://github.com/GSA/notifications-admin.git
synced 2025-12-10 15:13:40 -05:00
Patch update sections of the page on AJAX
Currently, when we update a section of the page with AJAX we replace the entire HTML of the section with the new HTML. This causes problems: - if you’re trying to interact with that section of the page, eg by inpecting it, clicking or hovering an element - (probably) for screenreaders trying to navigate a page which is changing more than is necessary This commit replaces the call to `.html()` with a pretty clever library called diffDOM[1]. DiffDOM works by taking a diff of the old element and the new element, then doing a patch update, ie only modifying the parts that have changed. This is similar in concept to React’s virtual DOM, while still allowing us to render all markup from one set of templates on the server-side. 1. https://github.com/fiduswriter/diffDOM
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
GOVUK.timeCache = {};
|
||||
GOVUK.resultCache = {};
|
||||
|
||||
var dd = new diffDOM();
|
||||
|
||||
let getter = function(resource, interval, render) {
|
||||
|
||||
if (
|
||||
@@ -21,8 +23,11 @@
|
||||
|
||||
};
|
||||
|
||||
let poller = (resource, key, component, interval) => () => getter(
|
||||
resource, interval, response => component.html(response[key])
|
||||
let poller = (resource, key, $component, interval) => () => getter(
|
||||
resource, interval, response => dd.apply(
|
||||
$component.get(0),
|
||||
dd.diff($component.get(0), $(response[key]).get(0))
|
||||
)
|
||||
);
|
||||
|
||||
Modules.UpdateContent = function() {
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
{% from "components/big-number.html" import big_number %}
|
||||
<ul class="grid-row job-totals">
|
||||
<li class="column-one-quarter">
|
||||
{{ big_number(
|
||||
counts.queued, 'queued'
|
||||
)}}
|
||||
</li>
|
||||
<li class="column-one-quarter">
|
||||
{{ big_number(
|
||||
counts.sent, 'processed'
|
||||
)}}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div
|
||||
{% if not finished_at %}
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}"
|
||||
data-key="counts"
|
||||
{% endif %}
|
||||
>
|
||||
|
||||
<ul class="grid-row job-totals">
|
||||
<li class="column-one-quarter">
|
||||
{{ big_number(
|
||||
counts.queued, 'queued'
|
||||
)}}
|
||||
</li>
|
||||
<li class="column-one-quarter">
|
||||
{{ big_number(
|
||||
counts.sent, 'processed'
|
||||
)}}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
{% from "components/table.html" import list_table, field, right_aligned_field_heading %}
|
||||
|
||||
{% call(item, row_number) list_table(
|
||||
notifications,
|
||||
caption=uploaded_file_name,
|
||||
caption_visible=False,
|
||||
empty_message="No messages to show yet",
|
||||
field_headings=[
|
||||
'Recipient',
|
||||
right_aligned_field_heading('Status')
|
||||
]
|
||||
) %}
|
||||
{% call field() %}
|
||||
{{ item.to }}
|
||||
{% endcall %}
|
||||
{% call field(
|
||||
align='right',
|
||||
status='error' if item.status == 'Failed' else 'default'
|
||||
) %}
|
||||
{{ item.status|title }} at {{ item.sent_at|format_time }}
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
<div
|
||||
{% if not finished_at %}
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}"
|
||||
data-key="notifications"
|
||||
{% endif %}
|
||||
>
|
||||
|
||||
<div>
|
||||
{% call(item, row_number) list_table(
|
||||
notifications,
|
||||
caption=uploaded_file_name,
|
||||
caption_visible=False,
|
||||
empty_message="No messages to show yet",
|
||||
field_headings=[
|
||||
'Recipient',
|
||||
right_aligned_field_heading('Status')
|
||||
]
|
||||
) %}
|
||||
{% call field() %}
|
||||
{{ item.to }}
|
||||
{% endcall %}
|
||||
{% call field(
|
||||
align='right',
|
||||
status='error' if item.status == 'Failed' else 'default'
|
||||
) %}
|
||||
{{ item.status|title }} at {{ item.sent_at|format_time }}
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
{% if finished_at %}
|
||||
<p class='heading-small'>
|
||||
Finished {{ finished_at|format_datetime }}
|
||||
</p>
|
||||
{% else %}
|
||||
<p class='heading-small'>
|
||||
Started {{ uploaded_at|format_datetime }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<div
|
||||
{% if not finished_at %}
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}"
|
||||
data-key="status"
|
||||
{% endif %}
|
||||
>
|
||||
|
||||
{% if finished_at %}
|
||||
<p class='heading-small'>
|
||||
Finished {{ finished_at|format_datetime }}
|
||||
</p>
|
||||
{% else %}
|
||||
<p class='heading-small'>
|
||||
Started {{ uploaded_at|format_datetime }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -18,13 +18,6 @@
|
||||
{% include 'views/dashboard/no-permissions-banner.html' %}
|
||||
{% endif %}
|
||||
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".service_dashboard_updates", service_id=current_service.id)}}"
|
||||
data-key="today"
|
||||
data-interval-seconds="10"
|
||||
>
|
||||
{% include 'views/dashboard/today.html' %}
|
||||
</div>
|
||||
{% include 'views/dashboard/today.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
{% from "components/big-number.html" import big_number_with_status %}
|
||||
|
||||
<h2 class="heading-medium">
|
||||
In the last 7 days
|
||||
</h2>
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-half">
|
||||
{{ big_number_with_status(
|
||||
statistics.get('emails_delivered', 0),
|
||||
'email' if statistics.get('emails_delivered') == 1 else 'emails',
|
||||
statistics.get('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, template_type='email', status='failed')
|
||||
) }}
|
||||
</div>
|
||||
<div class="column-half">
|
||||
{{ big_number_with_status(
|
||||
statistics.get('sms_requested', 0),
|
||||
'text message' if statistics.get('sms_requested') == 1 else 'text messages',
|
||||
statistics.get('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, template_type='sms', status='failed')
|
||||
) }}
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".service_dashboard_updates", service_id=current_service.id)}}"
|
||||
data-key="today"
|
||||
data-interval-seconds="2"
|
||||
>
|
||||
<h2 class="heading-medium">
|
||||
In the last 7 days
|
||||
</h2>
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-half">
|
||||
{{ big_number_with_status(
|
||||
statistics.get('emails_delivered', 0),
|
||||
'email' if statistics.get('emails_delivered') == 1 else 'emails',
|
||||
statistics.get('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, template_type='email', status='failed')
|
||||
) }}
|
||||
</div>
|
||||
<div class="column-half">
|
||||
{{ big_number_with_status(
|
||||
statistics.get('sms_requested', 0),
|
||||
'text message' if statistics.get('sms_requested') == 1 else 'text messages',
|
||||
statistics.get('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, template_type='sms', status='failed')
|
||||
) }}
|
||||
</div>
|
||||
</div>
|
||||
{% with period = "in the last 7 days" %}
|
||||
{% include 'views/dashboard/template-statistics.html' %}
|
||||
{% endwith %}
|
||||
<p class='table-show-more-link'>
|
||||
<a href="{{ url_for('.template_history', service_id=current_service.id) }}">See all templates used this year</a>
|
||||
</p>
|
||||
</div>
|
||||
{% with period = "in the last 7 days" %}
|
||||
{% include 'views/dashboard/template-statistics.html' %}
|
||||
{% endwith %}
|
||||
<p class='table-show-more-link'>
|
||||
<a href="{{ url_for('.template_history', service_id=current_service.id) }}">See all templates used this year</a>
|
||||
</p>
|
||||
|
||||
@@ -30,40 +30,10 @@
|
||||
)}}
|
||||
{% endif %}
|
||||
|
||||
{% if not finished_at %}
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}"
|
||||
data-key="status"
|
||||
>
|
||||
{% endif %}
|
||||
{% include 'partials/jobs/status.html' %}
|
||||
{% if not finished_at %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include 'partials/jobs/status.html' %}
|
||||
|
||||
{% if not finished_at %}
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}"
|
||||
data-key="counts"
|
||||
>
|
||||
{% endif %}
|
||||
{% include 'partials/jobs/count.html' %}
|
||||
{% if not finished_at %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include 'partials/jobs/count.html' %}
|
||||
|
||||
{% if not finished_at %}
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}"
|
||||
data-key="notifications"
|
||||
>
|
||||
{% endif %}
|
||||
{% include 'partials/jobs/notifications.html' %}
|
||||
{% if not finished_at %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include 'partials/jobs/notifications.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -68,7 +68,8 @@ gulp.task('javascripts', () => gulp
|
||||
.pipe(plugins.uglify())
|
||||
.pipe(plugins.addSrc.prepend([
|
||||
paths.npm + 'jquery/dist/jquery.min.js',
|
||||
paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js'
|
||||
paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js',
|
||||
paths.npm + 'diff-dom/diffDOM.js'
|
||||
]))
|
||||
.pipe(plugins.concat('all.js'))
|
||||
.pipe(gulp.dest(paths.dist + 'javascripts/'))
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"dependencies": {
|
||||
"babel-core": "6.3.26",
|
||||
"babel-preset-es2015": "6.3.13",
|
||||
"diff-dom": "2.0.3",
|
||||
"govuk-elements-sass": "1.1.1",
|
||||
"govuk_frontend_toolkit": "4.6.0",
|
||||
"govuk_template_jinja": "https://github.com/alphagov/govuk_template/releases/download/v0.17.1/jinja_govuk_template-0.17.1.tgz",
|
||||
|
||||
Reference in New Issue
Block a user