diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a87db3fcd..7ffbbc290 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -20,3 +20,8 @@ Please enter a detailed description here. * Consideration 1 * Consideration 2 * Consideration ... + +## A11y Checks (if applicable) + +* Conduct automated tests through [AxeDevTools](https://www.deque.com/axe/devtools/) and [WAVE](https://wave.webaim.org/) +* Review the [Manual Checklist](https://docs.google.com/document/d/192bBXStebdXWtYhZQ73qaWMJhGcuSB1W6c9YBXhWZvc/edit?usp=sharing) diff --git a/app/assets/javascripts/activityChart.js b/app/assets/javascripts/activityChart.js index 6dfc73fbb..f12774c68 100644 --- a/app/assets/javascripts/activityChart.js +++ b/app/assets/javascripts/activityChart.js @@ -2,6 +2,8 @@ if (document.getElementById('activityChartContainer')) { let currentType = 'service'; + const tableContainer = document.getElementById('activityContainer'); + const currentUserName = tableContainer.getAttribute('data-currentUserName'); const COLORS = { delivered: '#0076d6', failed: '#fa9441', @@ -282,27 +284,58 @@ subTitle.textContent = `${selectedText} - last 7 days`; fetchData(selectedValue); - // Update ARIA live region const liveRegion = document.getElementById('aria-live-account'); liveRegion.textContent = `Data updated for ${selectedText} - last 7 days`; - // Switch tables based on dropdown selection - const selectedTable = selectedValue === "individual" ? "table1" : "table2"; - const tables = document.querySelectorAll('.table-overflow-x-auto'); - tables.forEach(function(table) { - table.classList.add('hidden'); // Hide all tables by adding the hidden class - table.classList.remove('visible'); // Ensure they are not visible - }); - const tableToShow = document.getElementById(selectedTable); - tableToShow.classList.remove('hidden'); // Remove hidden class - tableToShow.classList.add('visible'); // Add visible class + const tableHeading = document.querySelector('#tableActivity h2'); + const senderColumns = document.querySelectorAll('.sender-column'); + const allRows = document.querySelectorAll('#activity-table tbody tr'); + const caption = document.querySelector('#activity-table caption'); + + if (selectedValue === 'individual') { + + tableHeading.textContent = 'My activity'; + caption.textContent = `Table showing the sent jobs for ${currentUserName}`; + + senderColumns.forEach(col => { + col.style.display = 'none'; + }); + + allRows.forEach(row => row.style.display = 'none'); + + const userRows = Array.from(allRows).filter(row => { + const senderCell = row.querySelector('.sender-column'); + const rowSender = senderCell ? senderCell.textContent.trim() : ''; + return rowSender === currentUserName; + }); + + userRows.slice(0, 5).forEach(row => { + row.style.display = ''; + }); + } else { + + tableHeading.textContent = 'Service activity'; + caption.textContent = `Table showing the sent jobs for service`; + + senderColumns.forEach(col => { + col.style.display = ''; + }); + + allRows.forEach((row, index) => { + row.style.display = (index < 5) ? '' : 'none'; + }); + } }; document.addEventListener('DOMContentLoaded', function() { // Initialize activityChart chart and table with service data by default fetchData(currentType); - // Add event listener to the dropdown + const allRows = Array.from(document.querySelectorAll('#activity-table tbody tr')); + allRows.forEach((row, index) => { + row.style.display = (index < 5) ? '' : 'none'; + }); + const dropdown = document.getElementById('options'); dropdown.addEventListener('change', handleDropdownChange); }); diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss index 7fafb8276..0bb1aab7e 100644 --- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss +++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss @@ -1024,7 +1024,3 @@ nav.nav { font-size: units(3); font-weight: bold; } - -.form-control-error { - border: 4px solid #b10e1e -} diff --git a/app/content/get-started.md b/app/content/get-started.md index 7d18aacbd..c97b9efc6 100644 --- a/app/content/get-started.md +++ b/app/content/get-started.md @@ -5,7 +5,7 @@ Explore Notify, add team members, and practice [sending messages to teammates](/using-notify/trial-mode). 2. ## Personalize content -Learn how to [personalize messages](/using-notify/guidance) to increase response. +Learn how to [personalize messages](/using-notify/how-to) to increase response. 3. ## Check delivery status [Analyze the delivery](/using-notify/delivery-status) of your messages and download reports diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 8013acb9d..1f8cac573 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -14,7 +14,7 @@ from app import ( service_api_client, template_statistics_client, ) -from app.formatters import format_date_numeric, format_datetime_numeric, get_time_left +from app.formatters import format_date_numeric, format_datetime_numeric from app.main import main from app.main.views.user_profile import set_timezone from app.statistics_utils import get_formatted_percentage @@ -62,32 +62,14 @@ def service_dashboard(service_id): job_response = job_api_client.get_jobs(service_id)["data"] service_data_retention_days = 7 - jobs = [ - { - "job_id": job["id"], - "time_left": get_time_left(job["created_at"]), - "download_link": url_for( - ".view_job_csv", service_id=current_service.id, job_id=job["id"] - ), - "view_job_link": url_for( - ".view_job", service_id=current_service.id, job_id=job["id"] - ), - "created_at": job["created_at"], - "processing_finished": job.get("processing_finished"), - "processing_started": job.get("processing_started"), - "notification_count": job["notification_count"], - "created_by": job["created_by"], - "template_name": job["template_name"], - "original_file_name": job["original_file_name"], - } - for job in job_response - if job["job_status"] != "cancelled" - ] + filtered_jobs = [job for job in job_response if job["job_status"] != "cancelled"] + sorted_jobs = sorted(filtered_jobs, key=lambda job: job["created_at"], reverse=True) + return render_template( "views/dashboard/dashboard.html", updates_url=url_for(".service_dashboard_updates", service_id=service_id), partials=get_dashboard_partials(service_id), - jobs=jobs, + jobs=sorted_jobs, service_data_retention_days=service_data_retention_days, sms_sent=sms_sent, sms_allowance_remaining=sms_allowance_remaining, diff --git a/app/main/views/index.py b/app/main/views/index.py index 8b63d2bd8..5c0312afc 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -217,11 +217,11 @@ def benchmark_performance(): ) -@main.route("/using-notify/guidance") +@main.route("/using-notify/how-to") @user_is_logged_in -def guidance_index(): +def how_to(): return render_template( - "views/guidance/index.html", + "views/how-to/index.html", navigation_links=using_notify_nav(), ) @@ -266,29 +266,29 @@ def join_notify(): ) -@main.route("/using-notify/guidance/create-and-send-messages") +@main.route("/using-notify/how-to/create-and-send-messages") @user_is_logged_in def create_and_send_messages(): return render_template( - "views/guidance/create-and-send-messages.html", + "views/how-to/create-and-send-messages.html", navigation_links=using_notify_nav(), ) -@main.route("/using-notify/guidance/edit-and-format-messages") +@main.route("/using-notify/how-to/edit-and-format-messages") @user_is_logged_in def edit_and_format_messages(): return render_template( - "views/guidance/edit-and-format-messages.html", + "views/how-to/edit-and-format-messages.html", navigation_links=using_notify_nav(), ) -@main.route("/using-notify/guidance/send-files-by-email") +@main.route("/using-notify/how-to/send-files-by-email") @user_is_logged_in def send_files_by_email(): return render_template( - "views/guidance/send-files-by-email.html", + "views/how-to/send-files-by-email.html", navigation_links=using_notify_nav(), ) diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index 3b2cf84c1..db086e511 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -2,7 +2,7 @@ def using_notify_nav(): nav_items = [ {"name": "Get started", "link": "main.get_started"}, { - "name": "Best Practices", + "name": "Best practices", "link": "main.best_practices", "sub_navigation_items": [ { @@ -33,8 +33,8 @@ def using_notify_nav(): }, {"name": "Trial mode", "link": "main.trial_mode_new"}, {"name": "Tracking usage", "link": "main.pricing"}, - {"name": "Delivery Status", "link": "main.message_status"}, - {"name": "Guidance", "link": "main.guidance_index"}, + {"name": "Delivery status", "link": "main.message_status"}, + {"name": "How to", "link": "main.how_to"}, ] return nav_items diff --git a/app/main/views/templates.py b/app/main/views/templates.py index 3a7315db7..5c59e1e7c 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -645,7 +645,6 @@ def edit_service_template(service_id, template_id): return render_template( "views/edit-{}-template.html".format(template["template_type"]), form=form, - errors=form.errors if form.errors else None, template=template, heading_action="Edit", ) diff --git a/app/navigation.py b/app/navigation.py index 424d03ae3..f20df4e5f 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -54,7 +54,7 @@ class HeaderNavigation(Navigation): "pricing", "trial_mode_new", "message_status", - "guidance_index", + "how_to", }, "accounts-or-dashboard": { "conversation", diff --git a/app/templates/components/components/input/template.njk b/app/templates/components/components/input/template.njk index 9e2cff08c..7f5634651 100644 --- a/app/templates/components/components/input/template.njk +++ b/app/templates/components/components/input/template.njk @@ -42,7 +42,5 @@ {%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %} {%- if params.autocomplete %} autocomplete="{{ params.autocomplete}}"{% endif %} {%- if params.pattern %} pattern="{{ params.pattern }}"{% endif %} - {%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor -%} - {%- if params.required %} required{% endif %} -/> + {%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}> diff --git a/app/templates/components/form.html b/app/templates/components/form.html index 5875a19a9..17cabc7f0 100644 --- a/app/templates/components/form.html +++ b/app/templates/components/form.html @@ -19,6 +19,7 @@ data-{{ key }}="{{ val }}" {% endif %} {% endfor %} + novalidate > {{ caller() }} diff --git a/app/templates/components/textbox.html b/app/templates/components/textbox.html index e8b6f813d..3e479cbce 100644 --- a/app/templates/components/textbox.html +++ b/app/templates/components/textbox.html @@ -13,13 +13,22 @@ safe_error_message=False, rows=8, extra_form_group_classes='', - placeholder='', - required=None + placeholder='' ) %}
+ {% if field.errors %} + + {% endif %}
{% endif %} - {% if field.errors %} - - Error: - {% if not safe_error_message %}{{ field.errors[0] }}{% else %}{{ field.errors[0]|safe }}{% endif %} - - {% endif %} {% if highlight_placeholders or autosize %} @@ -56,8 +59,6 @@ data_highlight_placeholders='true' if highlight_placeholders else 'false', rows=rows|string, placeholder=placeholder, - aria_describedby=field.name+"-error", - required='required' if required else None, **kwargs ) }} {% if suffix %} diff --git a/app/templates/views/dashboard/activity-table.html b/app/templates/views/dashboard/activity-table.html new file mode 100644 index 000000000..a40840033 --- /dev/null +++ b/app/templates/views/dashboard/activity-table.html @@ -0,0 +1,72 @@ +

Recent activity

+
+
+ + +
+
+
+
{{ current_service.name }} - last 7 days
+
+
+
+
+
+
+
+
+
+

Service activity

+ + + + + + + + + + + + + + + {% if jobs %} + {% for job in jobs %} + + + + + + + + {% endfor %} + {% else %} + + + + {% endif %} + +
Table showing the sent jobs for {{current_service.name}}
Job ID#TemplateJob statusSender + # of Recipients
+ + {{ job.id[:8] if job.id else 'Manually entered number' }} + + {{ job.template_name }} + {% if job.scheduled_for and not job.processing_finished %} + Scheduled for {{ job.scheduled_for|format_datetime_table }} + {% elif job.processing_finished and not job.statistics|selectattr('status', 'equalto', 'sending')|list %} + Sent on {{ job.processing_finished|format_datetime_table }} + {% elif job.processing_started %} + Sending since {{ job.processing_started|format_datetime_table }} + {% else %} + Pending since {{ job.created_at|format_datetime_table }} + {% endif %} + {{ job.created_by.name }}{{ job.notification_count }}
No batched job messages found  (messages are + kept for {{ service_data_retention_days }} days).
+
+
diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index 04abe1afc..bd19585c3 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -6,140 +6,38 @@ {% from "components/ajax-block.html" import ajax_block %} {% block service_page_title %} - Dashboard + Dashboard {% endblock %} {% block maincolumn_content %} - + -
+
-

Dashboard

- {% if current_user.has_permissions('manage_templates') and not current_service.all_templates %} - {% include 'views/dashboard/write-first-messages.html' %} - {% endif %} +

Dashboard

+{% if current_user.has_permissions('manage_templates') and not current_service.all_templates %} + {% include 'views/dashboard/write-first-messages.html' %} +{% endif %} - {{ ajax_block(partials, updates_url, 'upcoming') }} +{{ ajax_block(partials, updates_url, 'upcoming') }} -

{{ current_service.name }} Dashboard

+

{{ current_service.name }} Dashboard

- {{ ajax_block(partials, updates_url, 'inbox') }} +{{ ajax_block(partials, updates_url, 'inbox') }} -
-

Total messages

- -
-
-
+
+

Total messages

+ +
+
+
-

Recent activity

-
-
- - -
-
-
-
{{ current_service.name }} - last 7 days
-
-
-
-
-
-
-
+{% include 'views/dashboard/activity-table.html' %} - {% if current_user.has_permissions('manage_service') %}{% endif %} +{% if current_user.has_permissions('manage_service') %}{% endif %} -
- - -
-

Service activity

- - - - - - - - - - - - - {% if jobs %} - {% for job in jobs[:5] %} - {% set notification = job.notifications[0] %} - - - - - - - - {% endfor %} - {% else %} - - - - {% endif %} - -
Table showing the sent jobs for this service
Job ID#TemplateJob statusSender# of Recipients
- - {{ job.job_id[:8] if job.job_id else 'Manually entered number' }} - - {{ job.template_name }}Sent on - {{ (job.processing_finished if job.processing_finished else job.processing_started - if job.processing_started else job.created_at)|format_datetime_table }} - {{ job.created_by.name }}{{ job.notification_count }}
No batched job messages found  (messages are kept for {{ service_data_retention_days }} days).
-
-
- {{ ajax_block(partials, updates_url, 'template-statistics') }} -
+{{ ajax_block(partials, updates_url, 'template-statistics') }} +
{% endblock %} diff --git a/app/templates/views/edit-sms-template.html b/app/templates/views/edit-sms-template.html index 728b92cd6..97eac73dc 100644 --- a/app/templates/views/edit-sms-template.html +++ b/app/templates/views/edit-sms-template.html @@ -29,11 +29,9 @@ {% call form_wrapper() %}
-