mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-11 02:23:19 -04:00
Merge branch 'main' into 2199-add-pending-message-data-to-daily-and-user_daily-stats
This commit is contained in:
@@ -20,3 +20,8 @@ Please enter a detailed description here.
|
|||||||
* Consideration 1
|
* Consideration 1
|
||||||
* Consideration 2
|
* Consideration 2
|
||||||
* Consideration ...
|
* 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)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
if (document.getElementById('activityChartContainer')) {
|
if (document.getElementById('activityChartContainer')) {
|
||||||
let currentType = 'service';
|
let currentType = 'service';
|
||||||
|
const tableContainer = document.getElementById('activityContainer');
|
||||||
|
const currentUserName = tableContainer.getAttribute('data-currentUserName');
|
||||||
const COLORS = {
|
const COLORS = {
|
||||||
delivered: '#0076d6',
|
delivered: '#0076d6',
|
||||||
failed: '#fa9441',
|
failed: '#fa9441',
|
||||||
@@ -282,27 +284,58 @@
|
|||||||
subTitle.textContent = `${selectedText} - last 7 days`;
|
subTitle.textContent = `${selectedText} - last 7 days`;
|
||||||
fetchData(selectedValue);
|
fetchData(selectedValue);
|
||||||
|
|
||||||
// Update ARIA live region
|
|
||||||
const liveRegion = document.getElementById('aria-live-account');
|
const liveRegion = document.getElementById('aria-live-account');
|
||||||
liveRegion.textContent = `Data updated for ${selectedText} - last 7 days`;
|
liveRegion.textContent = `Data updated for ${selectedText} - last 7 days`;
|
||||||
|
|
||||||
// Switch tables based on dropdown selection
|
const tableHeading = document.querySelector('#tableActivity h2');
|
||||||
const selectedTable = selectedValue === "individual" ? "table1" : "table2";
|
const senderColumns = document.querySelectorAll('.sender-column');
|
||||||
const tables = document.querySelectorAll('.table-overflow-x-auto');
|
const allRows = document.querySelectorAll('#activity-table tbody tr');
|
||||||
tables.forEach(function(table) {
|
const caption = document.querySelector('#activity-table caption');
|
||||||
table.classList.add('hidden'); // Hide all tables by adding the hidden class
|
|
||||||
table.classList.remove('visible'); // Ensure they are not visible
|
if (selectedValue === 'individual') {
|
||||||
});
|
|
||||||
const tableToShow = document.getElementById(selectedTable);
|
tableHeading.textContent = 'My activity';
|
||||||
tableToShow.classList.remove('hidden'); // Remove hidden class
|
caption.textContent = `Table showing the sent jobs for ${currentUserName}`;
|
||||||
tableToShow.classList.add('visible'); // Add visible class
|
|
||||||
|
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() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Initialize activityChart chart and table with service data by default
|
// Initialize activityChart chart and table with service data by default
|
||||||
fetchData(currentType);
|
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');
|
const dropdown = document.getElementById('options');
|
||||||
dropdown.addEventListener('change', handleDropdownChange);
|
dropdown.addEventListener('change', handleDropdownChange);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1024,7 +1024,3 @@ nav.nav {
|
|||||||
font-size: units(3);
|
font-size: units(3);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control-error {
|
|
||||||
border: 4px solid #b10e1e
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
Explore Notify, add team members, and practice [sending messages to teammates](/using-notify/trial-mode).
|
Explore Notify, add team members, and practice [sending messages to teammates](/using-notify/trial-mode).
|
||||||
|
|
||||||
2. ## Personalize content
|
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
|
3. ## Check delivery status
|
||||||
[Analyze the delivery](/using-notify/delivery-status) of your messages and download reports
|
[Analyze the delivery](/using-notify/delivery-status) of your messages and download reports
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from app import (
|
|||||||
service_api_client,
|
service_api_client,
|
||||||
template_statistics_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 import main
|
||||||
from app.main.views.user_profile import set_timezone
|
from app.main.views.user_profile import set_timezone
|
||||||
from app.statistics_utils import get_formatted_percentage
|
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"]
|
job_response = job_api_client.get_jobs(service_id)["data"]
|
||||||
service_data_retention_days = 7
|
service_data_retention_days = 7
|
||||||
|
|
||||||
jobs = [
|
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)
|
||||||
"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"
|
|
||||||
]
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"views/dashboard/dashboard.html",
|
"views/dashboard/dashboard.html",
|
||||||
updates_url=url_for(".service_dashboard_updates", service_id=service_id),
|
updates_url=url_for(".service_dashboard_updates", service_id=service_id),
|
||||||
partials=get_dashboard_partials(service_id),
|
partials=get_dashboard_partials(service_id),
|
||||||
jobs=jobs,
|
jobs=sorted_jobs,
|
||||||
service_data_retention_days=service_data_retention_days,
|
service_data_retention_days=service_data_retention_days,
|
||||||
sms_sent=sms_sent,
|
sms_sent=sms_sent,
|
||||||
sms_allowance_remaining=sms_allowance_remaining,
|
sms_allowance_remaining=sms_allowance_remaining,
|
||||||
|
|||||||
@@ -217,11 +217,11 @@ def benchmark_performance():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@main.route("/using-notify/guidance")
|
@main.route("/using-notify/how-to")
|
||||||
@user_is_logged_in
|
@user_is_logged_in
|
||||||
def guidance_index():
|
def how_to():
|
||||||
return render_template(
|
return render_template(
|
||||||
"views/guidance/index.html",
|
"views/how-to/index.html",
|
||||||
navigation_links=using_notify_nav(),
|
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
|
@user_is_logged_in
|
||||||
def create_and_send_messages():
|
def create_and_send_messages():
|
||||||
return render_template(
|
return render_template(
|
||||||
"views/guidance/create-and-send-messages.html",
|
"views/how-to/create-and-send-messages.html",
|
||||||
navigation_links=using_notify_nav(),
|
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
|
@user_is_logged_in
|
||||||
def edit_and_format_messages():
|
def edit_and_format_messages():
|
||||||
return render_template(
|
return render_template(
|
||||||
"views/guidance/edit-and-format-messages.html",
|
"views/how-to/edit-and-format-messages.html",
|
||||||
navigation_links=using_notify_nav(),
|
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
|
@user_is_logged_in
|
||||||
def send_files_by_email():
|
def send_files_by_email():
|
||||||
return render_template(
|
return render_template(
|
||||||
"views/guidance/send-files-by-email.html",
|
"views/how-to/send-files-by-email.html",
|
||||||
navigation_links=using_notify_nav(),
|
navigation_links=using_notify_nav(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ def using_notify_nav():
|
|||||||
nav_items = [
|
nav_items = [
|
||||||
{"name": "Get started", "link": "main.get_started"},
|
{"name": "Get started", "link": "main.get_started"},
|
||||||
{
|
{
|
||||||
"name": "Best Practices",
|
"name": "Best practices",
|
||||||
"link": "main.best_practices",
|
"link": "main.best_practices",
|
||||||
"sub_navigation_items": [
|
"sub_navigation_items": [
|
||||||
{
|
{
|
||||||
@@ -33,8 +33,8 @@ def using_notify_nav():
|
|||||||
},
|
},
|
||||||
{"name": "Trial mode", "link": "main.trial_mode_new"},
|
{"name": "Trial mode", "link": "main.trial_mode_new"},
|
||||||
{"name": "Tracking usage", "link": "main.pricing"},
|
{"name": "Tracking usage", "link": "main.pricing"},
|
||||||
{"name": "Delivery Status", "link": "main.message_status"},
|
{"name": "Delivery status", "link": "main.message_status"},
|
||||||
{"name": "Guidance", "link": "main.guidance_index"},
|
{"name": "How to", "link": "main.how_to"},
|
||||||
]
|
]
|
||||||
|
|
||||||
return nav_items
|
return nav_items
|
||||||
|
|||||||
@@ -645,7 +645,6 @@ def edit_service_template(service_id, template_id):
|
|||||||
return render_template(
|
return render_template(
|
||||||
"views/edit-{}-template.html".format(template["template_type"]),
|
"views/edit-{}-template.html".format(template["template_type"]),
|
||||||
form=form,
|
form=form,
|
||||||
errors=form.errors if form.errors else None,
|
|
||||||
template=template,
|
template=template,
|
||||||
heading_action="Edit",
|
heading_action="Edit",
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ class HeaderNavigation(Navigation):
|
|||||||
"pricing",
|
"pricing",
|
||||||
"trial_mode_new",
|
"trial_mode_new",
|
||||||
"message_status",
|
"message_status",
|
||||||
"guidance_index",
|
"how_to",
|
||||||
},
|
},
|
||||||
"accounts-or-dashboard": {
|
"accounts-or-dashboard": {
|
||||||
"conversation",
|
"conversation",
|
||||||
|
|||||||
@@ -42,7 +42,5 @@
|
|||||||
{%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %}
|
{%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %}
|
||||||
{%- if params.autocomplete %} autocomplete="{{ params.autocomplete}}"{% endif %}
|
{%- if params.autocomplete %} autocomplete="{{ params.autocomplete}}"{% endif %}
|
||||||
{%- if params.pattern %} pattern="{{ params.pattern }}"{% endif %}
|
{%- if params.pattern %} pattern="{{ params.pattern }}"{% endif %}
|
||||||
{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}
|
{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}>
|
||||||
{%- if params.required %} required{% endif %}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
data-{{ key }}="{{ val }}"
|
data-{{ key }}="{{ val }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
novalidate
|
||||||
>
|
>
|
||||||
{{ caller() }}
|
{{ caller() }}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -13,13 +13,22 @@
|
|||||||
safe_error_message=False,
|
safe_error_message=False,
|
||||||
rows=8,
|
rows=8,
|
||||||
extra_form_group_classes='',
|
extra_form_group_classes='',
|
||||||
placeholder='',
|
placeholder=''
|
||||||
required=None
|
|
||||||
) %}
|
) %}
|
||||||
<div
|
<div
|
||||||
class="usa-form-group{% if field.errors %} usa-form-group--error{% endif %} {{ extra_form_group_classes }}"
|
class="form-group{% if field.errors %} form-group-error{% endif %} {{ extra_form_group_classes }}"
|
||||||
data-module="{% if autofocus %}autofocus{% elif colour_preview %}colour-preview{% endif %}"
|
data-module="{% if autofocus %}autofocus{% elif colour_preview %}colour-preview{% endif %}"
|
||||||
>
|
>
|
||||||
|
{% if field.errors %}
|
||||||
|
<div class="usa-alert usa-alert--error edit-textbox-error-mt" role="alert">
|
||||||
|
<div class="usa-alert__body">
|
||||||
|
<h4 class="usa-alert__heading">Error message</h4>
|
||||||
|
<p class="usa-alert__text" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}">
|
||||||
|
{% if not safe_error_message %}{{ field.errors[0] }}{% else %}{{ field.errors[0]|safe }}{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<label class="usa-label" for="{{ field.name }}">
|
<label class="usa-label" for="{{ field.name }}">
|
||||||
{% if label %}
|
{% if label %}
|
||||||
{{ label }}
|
{{ label }}
|
||||||
@@ -32,12 +41,6 @@
|
|||||||
{{ hint }}
|
{{ hint }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if field.errors %}
|
|
||||||
<span id="{{ field.name}}-error" class="usa-error-message" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}">
|
|
||||||
<span class="usa-sr-only">Error:</span>
|
|
||||||
{% if not safe_error_message %}{{ field.errors[0] }}{% else %}{{ field.errors[0]|safe }}{% endif %}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
{%
|
{%
|
||||||
if highlight_placeholders or autosize
|
if highlight_placeholders or autosize
|
||||||
%}
|
%}
|
||||||
@@ -56,8 +59,6 @@
|
|||||||
data_highlight_placeholders='true' if highlight_placeholders else 'false',
|
data_highlight_placeholders='true' if highlight_placeholders else 'false',
|
||||||
rows=rows|string,
|
rows=rows|string,
|
||||||
placeholder=placeholder,
|
placeholder=placeholder,
|
||||||
aria_describedby=field.name+"-error",
|
|
||||||
required='required' if required else None,
|
|
||||||
**kwargs
|
**kwargs
|
||||||
) }}
|
) }}
|
||||||
{% if suffix %}
|
{% if suffix %}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<h2 class="line-height-sans-2 margin-bottom-0 margin-top-4">Recent activity</h2>
|
||||||
|
<div id="activityChartContainer">
|
||||||
|
<form class="usa-form">
|
||||||
|
<label class="usa-label" for="options">Account</label>
|
||||||
|
<select class="usa-select margin-bottom-2" name="options" id="options">
|
||||||
|
<option value disabled>- Select -</option>
|
||||||
|
<option value="service" selected>{{ current_service.name }}</option>
|
||||||
|
<option value="individual">{{ current_user.name }}</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
<div id="activityChart">
|
||||||
|
<div class="chart-header">
|
||||||
|
<div class="chart-subtitle">{{ current_service.name }} - last 7 days</div>
|
||||||
|
<div class="chart-legend" role="region" aria-label="Legend"></div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container" id="weeklyChart"></div>
|
||||||
|
<table id="weeklyTable" class="usa-sr-only usa-table"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="aria-live-account" class="usa-sr-only" aria-live="polite"></div>
|
||||||
|
<div class="table-container" id="activityContainer" data-currentUserName="{{ current_user.name }}">
|
||||||
|
<div id="tableActivity" class="table-overflow-x-auto">
|
||||||
|
<h2 id="table-heading" class="margin-top-4 margin-bottom-1">Service activity</h2>
|
||||||
|
|
||||||
|
<table class="usa-table job-table" id="activity-table">
|
||||||
|
<caption class="usa-sr-only">Table showing the sent jobs for {{current_service.name}}</caption>
|
||||||
|
|
||||||
|
<thead class="table-field-headings">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="table-field-heading-first" id="jobId">Job ID#</th>
|
||||||
|
<th data-sortable scope="col" class="table-field-heading" scope="col">Template</th>
|
||||||
|
<th data-sortable scope="col" class="table-field-heading">Job status</th>
|
||||||
|
<th data-sortable scope="col" role="columnheader" class="table-field-heading sender-column">Sender
|
||||||
|
</th>
|
||||||
|
<th data-sortable scope="col" class="table-field-heading"># of Recipients</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% if jobs %}
|
||||||
|
{% for job in jobs %}
|
||||||
|
<tr id="{{ job.id }}">
|
||||||
|
<td class="table-field jobid" role="rowheader">
|
||||||
|
<a class="usa-link" href="{{ url_for('.view_job', service_id=current_service.id, job_id=job.id )}}">
|
||||||
|
{{ job.id[:8] if job.id else 'Manually entered number' }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="table-field template">{{ job.template_name }}</td>
|
||||||
|
<td class="table-field time-sent">
|
||||||
|
{% 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 %}
|
||||||
|
</td>
|
||||||
|
<td class="table-field sender sender-column">{{ job.created_by.name }}</td>
|
||||||
|
<td class="table-field count-of-recipients">{{ job.notification_count }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<tr class="table-row">
|
||||||
|
<td class="table-empty-message" colspan="10">No batched job messages found  (messages are
|
||||||
|
kept for {{ service_data_retention_days }} days).</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -6,140 +6,38 @@
|
|||||||
{% from "components/ajax-block.html" import ajax_block %}
|
{% from "components/ajax-block.html" import ajax_block %}
|
||||||
|
|
||||||
{% block service_page_title %}
|
{% block service_page_title %}
|
||||||
Dashboard
|
Dashboard
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block maincolumn_content %}
|
{% block maincolumn_content %}
|
||||||
<script type="text/javascript" src="{{ asset_url('js/setTimezone.js') }}"></script>
|
<script type="text/javascript" src="{{ asset_url('js/setTimezone.js') }}"></script>
|
||||||
|
|
||||||
|
|
||||||
<div class="dashboard margin-top-0 margin-bottom-2">
|
<div class="dashboard margin-top-0 margin-bottom-2">
|
||||||
|
|
||||||
<h1 class="usa-sr-only">Dashboard</h1>
|
<h1 class="usa-sr-only">Dashboard</h1>
|
||||||
{% if current_user.has_permissions('manage_templates') and not current_service.all_templates %}
|
{% if current_user.has_permissions('manage_templates') and not current_service.all_templates %}
|
||||||
{% include 'views/dashboard/write-first-messages.html' %}
|
{% include 'views/dashboard/write-first-messages.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ ajax_block(partials, updates_url, 'upcoming') }}
|
{{ ajax_block(partials, updates_url, 'upcoming') }}
|
||||||
|
|
||||||
<h2 class="font-body-2xl line-height-sans-2 margin-top-0">{{ current_service.name }} Dashboard</h2>
|
<h2 class="font-body-2xl line-height-sans-2 margin-top-0">{{ current_service.name }} Dashboard</h2>
|
||||||
|
|
||||||
{{ ajax_block(partials, updates_url, 'inbox') }}
|
{{ ajax_block(partials, updates_url, 'inbox') }}
|
||||||
|
|
||||||
<div id="totalMessageChartContainer" data-sms-sent="{{ sms_sent }}" data-sms-allowance-remaining="{{ sms_allowance_remaining }}">
|
<div id="totalMessageChartContainer" data-sms-sent="{{ sms_sent }}" data-sms-allowance-remaining="{{ sms_allowance_remaining }}">
|
||||||
<h2 id="chartTitle">Total messages</h2>
|
<h2 id="chartTitle">Total messages</h2>
|
||||||
<svg id="totalMessageChart"></svg>
|
<svg id="totalMessageChart"></svg>
|
||||||
<div id="message"></div>
|
<div id="message"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="totalMessageTable" class="margin-0"></div>
|
<div id="totalMessageTable" class="margin-0"></div>
|
||||||
|
|
||||||
<h2 class="line-height-sans-2 margin-bottom-0 margin-top-4">Recent activity</h2>
|
{% include 'views/dashboard/activity-table.html' %}
|
||||||
<div id="activityChartContainer">
|
|
||||||
<form class="usa-form">
|
|
||||||
<label class="usa-label" for="options">Account</label>
|
|
||||||
<select class="usa-select margin-bottom-2" name="options" id="options">
|
|
||||||
<option value disabled>- Select -</option>
|
|
||||||
<option value="service" selected>{{ current_service.name }}</option>
|
|
||||||
<option value="individual">{{ current_user.name }}</option>
|
|
||||||
</select>
|
|
||||||
</form>
|
|
||||||
<div id="activityChart">
|
|
||||||
<div class="chart-header">
|
|
||||||
<div class="chart-subtitle">{{ current_service.name }} - last 7 days</div>
|
|
||||||
<div class="chart-legend" role="region" aria-label="Legend"></div>
|
|
||||||
</div>
|
|
||||||
<div class="chart-container" id="weeklyChart"></div>
|
|
||||||
<table id="weeklyTable" class="usa-sr-only usa-table"></table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="aria-live-account" class="usa-sr-only" aria-live="polite"></div>
|
|
||||||
|
|
||||||
{% if current_user.has_permissions('manage_service') %}{% endif %}
|
{% if current_user.has_permissions('manage_service') %}{% endif %}
|
||||||
|
|
||||||
<div class="table-container">
|
{{ ajax_block(partials, updates_url, 'template-statistics') }}
|
||||||
<div id="table1" class="table-overflow-x-auto hidden">
|
</div>
|
||||||
<h2 class="margin-top-4 margin-bottom-1">My activity</h2>
|
|
||||||
<table class="usa-table job-table">
|
|
||||||
<caption class="usa-sr-only">Table showing the sent jobs for {{current_user.name}}</caption>
|
|
||||||
<thead class="table-field-headings">
|
|
||||||
<tr>
|
|
||||||
<th scope="col" class="table-field-heading-first" id="jobId"><span>Job ID#</span></th>
|
|
||||||
<th data-sortable scope="col" class="table-field-heading"><span>Template</span></th>
|
|
||||||
<th data-sortable scope="col" class="table-field-heading"><span>Job status</span></th>
|
|
||||||
<th data-sortable scope="col" class="table-field-heading"><span># of Recipients</span></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% if jobs %}
|
|
||||||
{% for job in jobs[:5] %}
|
|
||||||
{% if job.created_by.name == current_user.name %}
|
|
||||||
{% set notification = job.notifications[0] %}
|
|
||||||
<tr id="{{ job.job_id }}">
|
|
||||||
<td class="table-field jobid" role="rowheader">
|
|
||||||
<a class="usa-link" href="{{ job.view_job_link }}">
|
|
||||||
{{ job.job_id[:8] if job.job_id else 'Manually entered number' }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="table-field template">{{ job.template_name }}</td>
|
|
||||||
<td class="table-field time-sent">Sent on
|
|
||||||
{{ (job.processing_finished if job.processing_finished else job.processing_started
|
|
||||||
if job.processing_started else job.created_at)|format_datetime_table }}
|
|
||||||
</td>
|
|
||||||
<td class="table-field count-of-recipients">{{ job.notification_count }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr class="table-row">
|
|
||||||
<td class="table-empty-message" colspan="10">No batched job messages found  (messages are kept for {{ service_data_retention_days }} days).</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="table2" class="table-overflow-x-auto visible">
|
|
||||||
<h2 class="margin-top-4 margin-bottom-1">Service activity</h2>
|
|
||||||
<table class="usa-table job-table">
|
|
||||||
<caption class="usa-sr-only">Table showing the sent jobs for this service</caption>
|
|
||||||
<thead class="table-field-headings">
|
|
||||||
<tr>
|
|
||||||
<th scope="col" role="columnheader" class="table-field-heading-first" id="jobId"><span>Job ID#</span></th>
|
|
||||||
<th data-sortable scope="col" role="columnheader" class="table-field-heading"><span>Template</span></th>
|
|
||||||
<th data-sortable scope="col" role="columnheader" class="table-field-heading"><span>Job status</span></th>
|
|
||||||
<th data-sortable scope="col" role="columnheader" class="table-field-heading"><span>Sender</span></th>
|
|
||||||
<th data-sortable scope="col" role="columnheader" class="table-field-heading"><span># of Recipients</span></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% if jobs %}
|
|
||||||
{% for job in jobs[:5] %}
|
|
||||||
{% set notification = job.notifications[0] %}
|
|
||||||
<tr id="{{ job.job_id }}">
|
|
||||||
<td class="table-field jobid" role="rowheader">
|
|
||||||
<a class="usa-link" href="{{ job.view_job_link }}">
|
|
||||||
{{ job.job_id[:8] if job.job_id else 'Manually entered number' }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="table-field template">{{ job.template_name }}</td>
|
|
||||||
<td class="table-field time-sent">Sent on
|
|
||||||
{{ (job.processing_finished if job.processing_finished else job.processing_started
|
|
||||||
if job.processing_started else job.created_at)|format_datetime_table }}
|
|
||||||
</td>
|
|
||||||
<td class="table-field sender">{{ job.created_by.name }}</td>
|
|
||||||
<td class="table-field count-of-recipients">{{ job.notification_count }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr class="table-row">
|
|
||||||
<td class="table-empty-message" colspan="10">No batched job messages found  (messages are kept for {{ service_data_retention_days }} days).</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ ajax_block(partials, updates_url, 'template-statistics') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -29,11 +29,9 @@
|
|||||||
|
|
||||||
{% call form_wrapper() %}
|
{% call form_wrapper() %}
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="tablet:grid-col-9 mobile-lg:grid-col-12" aria-live="polite" role="alert">
|
<div class="tablet:grid-col-9 mobile-lg:grid-col-12">
|
||||||
{{ form.name(param_extensions={
|
{{ form.name(param_extensions={
|
||||||
"extra_form_group_classes": "margin-bottom-2",
|
"extra_form_group_classes": "margin-bottom-2",
|
||||||
"id": "name",
|
|
||||||
"required": True,
|
|
||||||
"hint": {"text": "Your recipients will not see this"}
|
"hint": {"text": "Your recipients will not see this"}
|
||||||
}) }}
|
}) }}
|
||||||
{{ textbox(
|
{{ textbox(
|
||||||
@@ -43,8 +41,7 @@
|
|||||||
hint=content_hint,
|
hint=content_hint,
|
||||||
rows=5,
|
rows=5,
|
||||||
extra_form_group_classes='margin-bottom-1',
|
extra_form_group_classes='margin-bottom-1',
|
||||||
placeholder='Edit me! Check out the Personalization section below for details on cool ((stuff)) you can do with your messages!',
|
placeholder='Edit me! Check out the Personalization section below for details on cool ((stuff)) you can do with your messages!'
|
||||||
required=True
|
|
||||||
) }}
|
) }}
|
||||||
{% if current_user.platform_admin %}
|
{% if current_user.platform_admin %}
|
||||||
{{ form.process_type }}
|
{{ form.process_type }}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<h2 class="heading-medium" id="personalised-messages">Personalized content</h2>
|
<h2 class="heading-medium" id="personalised-messages">Personalized content</h2>
|
||||||
<p class="usa-body">Notify makes it easy to send personalized messages from a single template.</p>
|
<p class="usa-body">Notify makes it easy to send personalized messages from a single template.</p>
|
||||||
<p class="usa-body">See <a class="usa-link" href="{{ url_for('.guidance_index', _anchor='personalized-content') }}">how to personalize your content</a>.</p>
|
<p class="usa-body">See <a class="usa-link" href="{{ url_for('.how_to', _anchor='personalized-content') }}">how to personalize your content</a>.</p>
|
||||||
|
|
||||||
<h2 class="heading-medium" id="bulk-sending">Bulk sending</h2>
|
<h2 class="heading-medium" id="bulk-sending">Bulk sending</h2>
|
||||||
<p class="usa-body">To send a batch of messages at once, upload a list of contact details to Notify. You can also schedule the date and time you want them to be sent.</p>
|
<p class="usa-body">To send a batch of messages at once, upload a list of contact details to Notify. You can also schedule the date and time you want them to be sent.</p>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
{{ breadcrumbs.breadcrumb(page_title, "Best Practices", "main.best_practices") }}
|
{{ breadcrumbs.breadcrumb(page_title, "Best practices", "main.best_practices") }}
|
||||||
|
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>{{page_title}}</h1>
|
<h1>{{page_title}}</h1>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% set page_title = "Best Practices" %}
|
{% set page_title = "Best practices" %}
|
||||||
|
|
||||||
{% block per_page_title %}
|
{% block per_page_title %}
|
||||||
{{page_title}}
|
{{page_title}}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>Best Practices</h1>
|
<h1>Best practices</h1>
|
||||||
<p class="font-sans-lg text-base">For texting the public</p>
|
<p class="font-sans-lg text-base">For texting the public</p>
|
||||||
<p>Effectively reaching your audience and supporting your program’s goals starts with strategically planning out what
|
<p>Effectively reaching your audience and supporting your program’s goals starts with strategically planning out what
|
||||||
text messages can help you achieve and how to approach a thoughtful rollout.
|
text messages can help you achieve and how to approach a thoughtful rollout.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
{{ breadcrumbs.breadcrumb(page_title, "Best Practices", "main.best_practices") }}
|
{{ breadcrumbs.breadcrumb(page_title, "Best practices", "main.best_practices") }}
|
||||||
|
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>{{page_title}}</h1>
|
<h1>{{page_title}}</h1>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
{{ breadcrumbs.breadcrumb(page_title, "Best Practices", "main.best_practices") }}
|
{{ breadcrumbs.breadcrumb(page_title, "Best practices", "main.best_practices") }}
|
||||||
|
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>{{page_title}}</h1>
|
<h1>{{page_title}}</h1>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
{{ breadcrumbs.breadcrumb(page_title, "Best Practices", "main.best_practices") }}
|
{{ breadcrumbs.breadcrumb(page_title, "Best practices", "main.best_practices") }}
|
||||||
|
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>{{page_title}}</h1>
|
<h1>{{page_title}}</h1>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
{{ breadcrumbs.breadcrumb(page_title, "Best Practices", "main.best_practices") }}
|
{{ breadcrumbs.breadcrumb(page_title, "Best practices", "main.best_practices") }}
|
||||||
|
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>{{page_title}}</h1>
|
<h1>{{page_title}}</h1>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
{{ breadcrumbs.breadcrumb(page_title, "Best Practices", "main.best_practices") }}
|
{{ breadcrumbs.breadcrumb(page_title, "Best practices", "main.best_practices") }}
|
||||||
|
|
||||||
<section class="usa-prose">
|
<section class="usa-prose">
|
||||||
<h1>{{page_title}}</h1>
|
<h1>{{page_title}}</h1>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
{% from "components/service-link.html" import service_link %}
|
{% from "components/service-link.html" import service_link %}
|
||||||
|
|
||||||
{% block per_page_title %}
|
{% block per_page_title %}
|
||||||
Guidance
|
How to
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content_column_content %}
|
{% block content_column_content %}
|
||||||
<h1 class="font-body-2xl margin-bottom-3">Guidance</h1>
|
<h1 class="font-body-2xl margin-bottom-3">How to</h1>
|
||||||
|
|
||||||
<p>Notify allows you to easily create templates for messages for your recipients. You can customize messages to encourage
|
<p>Notify allows you to easily create templates for messages for your recipients. You can customize messages to encourage
|
||||||
your recipient to manage their benefits and increase follow-through.</p>
|
your recipient to manage their benefits and increase follow-through.</p>
|
||||||
@@ -61,7 +61,7 @@ your recipient to manage their benefits and increase follow-through.</p>
|
|||||||
<ol class="list">
|
<ol class="list">
|
||||||
<li>Add a placeholder to your content by placing two brackets around the personalized elements.</li>
|
<li>Add a placeholder to your content by placing two brackets around the personalized elements.</li>
|
||||||
<li>You can manually enter the personalized content or you can upload a spreadsheet with the details and let Notify do the
|
<li>You can manually enter the personalized content or you can upload a spreadsheet with the details and let Notify do the
|
||||||
work for you. See <a href="#prepare-data">data preparation</a>.</li>
|
work for you.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
@@ -80,7 +80,7 @@ all or part of the message contingent upon specific criteria associated with the
|
|||||||
<ol class="list">
|
<ol class="list">
|
||||||
<li>Use two brackets and ?? to define the conditional content.</li>
|
<li>Use two brackets and ?? to define the conditional content.</li>
|
||||||
<li>You can manually enter the conditional content or you can upload a spreadsheet with the personal details and let Notify
|
<li>You can manually enter the conditional content or you can upload a spreadsheet with the personal details and let Notify
|
||||||
do the work for you. See <a href="#prepare-data">data preparation</a>.</li>
|
do the work for you.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h4>Examples</h4>
|
<h4>Examples</h4>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
{% set product_highlights = [
|
{% set product_highlights = [
|
||||||
{
|
{
|
||||||
"svg_src": "#chat",
|
"svg_src": "#chat",
|
||||||
"card_heading": "Up to 250,000 messages to use over your first year*",
|
"card_heading": "Up to 100,000 messages to use over your first year*",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"svg_src": "#phone",
|
"svg_src": "#phone",
|
||||||
|
|||||||
@@ -37,8 +37,8 @@
|
|||||||
data_kwargs={'force-focus': True}
|
data_kwargs={'force-focus': True}
|
||||||
) %}
|
) %}
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="grid-col-12 {% if form.placeholder_value.label.text == 'phone number' %}extra-tracking{% endif %}">
|
<div class="grid-col-12 {% if form.placeholder_value.label.text == 'phone number' %}extra-tracking{% endif %}" aria-live="polite" role="alert">
|
||||||
{{ form.placeholder_value(param_extensions={"id": "phone-number"}) }}
|
{{ form.placeholder_value(param_extensions={"classes": ""}) }}
|
||||||
</div>
|
</div>
|
||||||
{% if skip_link or link_to_upload %}
|
{% if skip_link or link_to_upload %}
|
||||||
<div class="grid-col-12 margin-top-1">
|
<div class="grid-col-12 margin-top-1">
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
<h1 class="font-body-2xl margin-bottom-3">Contact us</h1>
|
<h1 class="font-body-2xl margin-bottom-3">Contact us</h1>
|
||||||
<p>Notify is designed to be easy to use.</p>
|
<p>Notify is designed to be easy to use.</p>
|
||||||
<ul class="list list-bullet">
|
<ul class="list list-bullet">
|
||||||
<li>For information on personalization and data preparation, see <a href={{ url_for("main.guidance_index") }}>Guidance</a>.</li>
|
<li>For information on personalization, see <a href={{ url_for("main.how_to") }}>How to</a>.</li>
|
||||||
<li>For help interpreting delivery reports, see <a href={{ url_for("main.message_status") }}>Delivery Status</a>.</li>
|
<li>For help interpreting delivery reports, see <a href={{ url_for("main.message_status") }}>Delivery status</a>.</li>
|
||||||
<li>For details on pricing and what counts as a message part, see <a href={{ url_for("main.pricing") }}>Pricing</a>.</li>
|
<li>For details on pricing and what counts as a message part, see <a href={{ url_for("main.pricing") }}>Pricing</a>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -90,4 +90,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--<div class="">
|
||||||
|
{{ copy_to_clipboard(template.id, name="Template ID", thing='template ID') }}
|
||||||
|
</div>-->
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -657,9 +657,8 @@ def test_should_show_recent_templates_on_dashboard(
|
|||||||
]
|
]
|
||||||
assert "Total messages" in headers
|
assert "Total messages" in headers
|
||||||
|
|
||||||
table_rows = page.find_all("tbody")[0].find_all("tr")
|
table_rows = page.find_all("tbody")[1].find_all("tr")
|
||||||
|
assert len(table_rows) == 2
|
||||||
assert len(table_rows) == 0
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@@ -1943,7 +1942,6 @@ def test_service_dashboard_shows_batched_jobs(
|
|||||||
job_table_body = page.find("table", class_="job-table")
|
job_table_body = page.find("table", class_="job-table")
|
||||||
|
|
||||||
rows = job_table_body.find_all("tbody")[0].find_all("tr")
|
rows = job_table_body.find_all("tbody")[0].find_all("tr")
|
||||||
|
assert len(rows) == 1
|
||||||
assert len(rows) == 0
|
|
||||||
|
|
||||||
assert job_table_body is not None
|
assert job_table_body is not None
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ def test_hiding_pages_from_search_engines(
|
|||||||
"message_status",
|
"message_status",
|
||||||
"how_to_pay",
|
"how_to_pay",
|
||||||
"get_started",
|
"get_started",
|
||||||
"guidance_index",
|
"how_to",
|
||||||
"create_and_send_messages",
|
"create_and_send_messages",
|
||||||
"edit_and_format_messages",
|
"edit_and_format_messages",
|
||||||
"send_files_by_email",
|
"send_files_by_email",
|
||||||
|
|||||||
@@ -1521,7 +1521,7 @@ def test_link_to_upload_not_offered_when_entering_personalisation(
|
|||||||
|
|
||||||
# We’re entering personalization
|
# We’re entering personalization
|
||||||
assert page.select_one("input[type=text]")["name"] == "placeholder_value"
|
assert page.select_one("input[type=text]")["name"] == "placeholder_value"
|
||||||
assert page.select_one("label[for=phone-number]").text.strip() == "name"
|
assert page.select_one("label[for=placeholder_value]").text.strip() == "name"
|
||||||
# No ‘Upload’ link shown
|
# No ‘Upload’ link shown
|
||||||
assert len(page.select("main a")) == 0
|
assert len(page.select("main a")) == 0
|
||||||
assert "Upload" not in page.select_one("main").text
|
assert "Upload" not in page.select_one("main").text
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ def test_should_show_empty_text_box(
|
|||||||
# shouldn’t also be set on the textbox itself
|
# shouldn’t also be set on the textbox itself
|
||||||
assert "data-module" not in textbox
|
assert "data-module" not in textbox
|
||||||
assert (
|
assert (
|
||||||
normalize_spaces(page.select_one("label[for=phone-number]").text) == "one"
|
normalize_spaces(page.select_one("label[for=placeholder_value]").text) == "one"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ EXCLUDED_ENDPOINTS = tuple(
|
|||||||
"get_started_old",
|
"get_started_old",
|
||||||
"go_to_dashboard_after_tour",
|
"go_to_dashboard_after_tour",
|
||||||
"guest_list",
|
"guest_list",
|
||||||
"guidance_index",
|
"how_to",
|
||||||
"history",
|
"history",
|
||||||
"how_to_pay",
|
"how_to_pay",
|
||||||
"inbound_sms_admin",
|
"inbound_sms_admin",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Object.defineProperty(HTMLElement.prototype, 'clientWidth', {
|
|||||||
beforeAll(done => {
|
beforeAll(done => {
|
||||||
// Set up the DOM with the D3 script included
|
// Set up the DOM with the D3 script included
|
||||||
document.body.innerHTML = `
|
document.body.innerHTML = `
|
||||||
<div id="activityChartContainer"">
|
<div id="activityChartContainer">
|
||||||
<form class="usa-form">
|
<form class="usa-form">
|
||||||
<label class="usa-label" for="options">Account</label>
|
<label class="usa-label" for="options">Account</label>
|
||||||
<select class="usa-select margin-bottom-2" name="options" id="options">
|
<select class="usa-select margin-bottom-2" name="options" id="options">
|
||||||
@@ -40,6 +40,9 @@ beforeAll(done => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="aria-live-account" class="usa-sr-only" aria-live="polite"></div>
|
<div id="aria-live-account" class="usa-sr-only" aria-live="polite"></div>
|
||||||
|
<div id="activityContainer" data-currentUserName="Test User"></div>
|
||||||
|
|
||||||
|
<div id="aria-live-account" class="usa-sr-only" aria-live="polite"></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Load the D3 script dynamically
|
// Load the D3 script dynamically
|
||||||
@@ -215,3 +218,59 @@ test('Fetches data and creates chart and table correctly', async () => {
|
|||||||
const rows = table.getElementsByTagName('tr');
|
const rows = table.getElementsByTagName('tr');
|
||||||
expect(rows.length).toBe(8);
|
expect(rows.length).toBe(8);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('handleDropdownChange updates DOM for individual selection', () => {
|
||||||
|
document.body.innerHTML = `
|
||||||
|
<div id="activityChartContainer">
|
||||||
|
<div class="chart-subtitle"></div>
|
||||||
|
</div>
|
||||||
|
<div id="aria-live-account"></div>
|
||||||
|
<div id="activityContainer" data-currentUserName="Test User"></div>
|
||||||
|
<div id="tableActivity">
|
||||||
|
<h2 id="table-heading"></h2>
|
||||||
|
<table id="activity-table">
|
||||||
|
<caption id="caption"></caption>
|
||||||
|
<tbody>
|
||||||
|
<tr><td class="sender-column">Test User</td></tr>
|
||||||
|
<tr><td class="sender-column">Other User</td></tr>
|
||||||
|
<tr><td class="sender-column">Test User</td></tr>
|
||||||
|
<tr><td class="sender-column">Test User</td></tr>
|
||||||
|
<tr><td class="sender-column">Other User</td></tr>
|
||||||
|
<tr><td class="sender-column">Test User</td></tr>
|
||||||
|
<tr><td class="sender-column">Test User</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<select id="options">
|
||||||
|
<option value="service">Service</option>
|
||||||
|
<option value="individual">Individual</option>
|
||||||
|
</select>
|
||||||
|
`;
|
||||||
|
|
||||||
|
window.currentUserName = "Test User";
|
||||||
|
|
||||||
|
jest.spyOn(window, 'fetchData').mockImplementation(() => {});
|
||||||
|
|
||||||
|
const selectElement = document.getElementById('options');
|
||||||
|
selectElement.value = 'individual';
|
||||||
|
const event = { target: selectElement };
|
||||||
|
|
||||||
|
window.handleDropdownChange(event);
|
||||||
|
|
||||||
|
expect(document.getElementById('table-heading').textContent).toBe('My activity');
|
||||||
|
expect(document.getElementById('caption').textContent).toContain('Test User');
|
||||||
|
|
||||||
|
document.querySelectorAll('.sender-column').forEach(col => {
|
||||||
|
expect(col.style.display).toBe('none');
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = Array.from(document.querySelectorAll('#activity-table tbody tr'));
|
||||||
|
const visibleRows = rows.filter(row => row.style.display !== 'none');
|
||||||
|
expect(visibleRows.length).toBeLessThanOrEqual(5);
|
||||||
|
visibleRows.forEach(row => {
|
||||||
|
const sender = row.querySelector('.sender-column').textContent.trim();
|
||||||
|
expect(sender).toBe('Test User');
|
||||||
|
});
|
||||||
|
|
||||||
|
window.fetchData.mockRestore();
|
||||||
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const sublinks = [
|
|||||||
{ label: 'Trial Mode', path: '/using-notify/trial-mode' },
|
{ label: 'Trial Mode', path: '/using-notify/trial-mode' },
|
||||||
{ label: 'Pricing', path: '/using-notify/pricing' },
|
{ label: 'Pricing', path: '/using-notify/pricing' },
|
||||||
{ label: 'Delivery Status', path: '/using-notify/delivery-status' },
|
{ label: 'Delivery Status', path: '/using-notify/delivery-status' },
|
||||||
{ label: 'Guidance', path: '/using-notify/guidance' },
|
{ label: 'How To', path: '/using-notify/how-to' },
|
||||||
{ label: 'Support', path: '/support' },
|
{ label: 'Support', path: '/support' },
|
||||||
{ label: 'Best Practices', path: '/using-notify/best-practices' },
|
{ label: 'Best Practices', path: '/using-notify/best-practices' },
|
||||||
{ label: 'Clear Goals', path: '/using-notify/best-practices/clear-goals' },
|
{ label: 'Clear Goals', path: '/using-notify/best-practices/clear-goals' },
|
||||||
|
|||||||
Reference in New Issue
Block a user