diff --git a/.ds.baseline b/.ds.baseline index c64d22627..56c3afc7d 100644 --- a/.ds.baseline +++ b/.ds.baseline @@ -161,7 +161,7 @@ "filename": "app/config.py", "hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc", "is_verified": false, - "line_number": 125, + "line_number": 123, "is_secret": false } ], @@ -684,5 +684,5 @@ } ] }, - "generated_at": "2024-11-14T15:53:44Z" + "generated_at": "2024-11-21T23:08:45Z" } diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index f002bb3fc..c3ef5dcbb 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -144,6 +144,7 @@ jobs: inputs: requirements.txt ignore-vulns: | PYSEC-2024-60 + PYSEC-2022-43162 - name: Run npm audit run: make npm-audit diff --git a/app/__init__.py b/app/__init__.py index 64580fcc1..4d89cd59e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,8 +1,9 @@ import os import pathlib +import secrets from functools import partial from time import monotonic -from urllib.parse import urlparse, urlunparse +from urllib.parse import unquote, urlparse, urlunparse import jinja2 from flask import ( @@ -114,6 +115,7 @@ from notifications_utils.formatters import ( get_lines_with_normalised_whitespace, ) from notifications_utils.recipients import format_phone_number_human_readable +from notifications_utils.url_safe_token import generate_token login_manager = LoginManager() csrf = CSRFProtect() @@ -168,10 +170,38 @@ def create_app(application): @application.context_processor def inject_feature_flags(): - feature_best_practices_enabled = application.config[ - "FEATURE_BEST_PRACTICES_ENABLED" - ] - return dict(FEATURE_BEST_PRACTICES_ENABLED=feature_best_practices_enabled) + feature_best_practices_enabled = application.config.get("FEATURE_BEST_PRACTICES_ENABLED", False) + feature_about_page_enabled = application.config.get("FEATURE_ABOUT_PAGE_ENABLED", False) + return dict( + FEATURE_BEST_PRACTICES_ENABLED=feature_best_practices_enabled, + FEATURE_ABOUT_PAGE_ENABLED=feature_about_page_enabled, + ) + + @application.context_processor + def inject_initial_signin_url(): + ttl = 24 * 60 * 60 + + # make and store the state + state = generate_token( + str(request.remote_addr), + current_app.config["SECRET_KEY"], + current_app.config["DANGEROUS_SALT"], + ) + + state_key = f"login-state-{unquote(state)}" + redis_client.set(state_key, state, ex=ttl) + + # make and store the nonce + nonce = secrets.token_urlsafe() + nonce_key = f"login-nonce-{unquote(nonce)}" + redis_client.set(nonce_key, nonce, ex=ttl) + + url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") + if url is not None: + url = url.replace("NONCE", nonce) + url = url.replace("STATE", state) + + return {'initial_signin_url': url} notify_environment = os.environ["NOTIFY_ENVIRONMENT"] diff --git a/app/assets/images/alarm.svg b/app/assets/images/alarm.svg new file mode 100644 index 000000000..57e6180bc --- /dev/null +++ b/app/assets/images/alarm.svg @@ -0,0 +1 @@ + diff --git a/app/assets/images/alert.svg b/app/assets/images/alert.svg new file mode 100644 index 000000000..d0d516d8f --- /dev/null +++ b/app/assets/images/alert.svg @@ -0,0 +1 @@ + diff --git a/app/assets/images/calendar.svg b/app/assets/images/calendar.svg new file mode 100644 index 000000000..9b755e9fd --- /dev/null +++ b/app/assets/images/calendar.svg @@ -0,0 +1 @@ + diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss index 377e28705..b5c87d821 100644 --- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss +++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss @@ -676,28 +676,28 @@ details form { margin-top: 0; } -ol.best-practices-list { +ol.guides-list { counter-reset: item; list-style-type: none; padding-left: 0; } -ol.best-practices-list.set-two { +ol.guides-list.set-two { counter-reset: item 6; } -ol.best-practices-list.set-three { +ol.guides-list.set-three { counter-reset: item 10; } -ol.best-practices-list li { +ol.guides-list li { counter-increment: item; margin-bottom: 15px; position: relative; padding-left: 40px; } -ol.best-practices-list li::before { +ol.guides-list li::before { content: counter(item); background-color: #005ea2; color: white; @@ -713,11 +713,11 @@ ol.best-practices-list li::before { top: 0; } -li.best-practices { +li.guides { padding-bottom: 50px; } -div.best-practices { +div.guides { height: 400px } @@ -820,7 +820,7 @@ $do-dont-top-bar-width: 1; } @media (max-width: 758px) { - .best-practices-flex-container { + .guides-flex-container { flex-direction: column; } } @@ -899,6 +899,7 @@ li.linked-card:hover svg, } .icon-list { + display: flex; width: 24px; height: 24px; padding: 2px 1px; diff --git a/app/config.py b/app/config.py index f40b46dea..146230047 100644 --- a/app/config.py +++ b/app/config.py @@ -91,9 +91,7 @@ class Config(object): getenv("FEATURE_BEST_PRACTICES_ENABLED", "false") == "true" ) - FEATURE_ABOUT_PAGE_ENABLED = ( - getenv("FEATURE_ABOUT_PAGE_ENABLED", "false") == "true" - ) + FEATURE_ABOUT_PAGE_ENABLED = getenv("FEATURE_ABOUT_PAGE_ENABLED", "false") == "true" def _s3_credentials_from_env(bucket_prefix): diff --git a/app/main/views/index.py b/app/main/views/index.py index 9b78dcc98..1b28f81dc 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -1,11 +1,15 @@ -import os -import secrets -from urllib.parse import unquote - -from flask import abort, current_app, redirect, render_template, request, url_for +from flask import ( + abort, + current_app, + jsonify, + redirect, + render_template, + request, + url_for, +) from flask_login import current_user -from app import redis_client, status_api_client +from app import status_api_client from app.formatters import apply_html_class, convert_markdown_template from app.main import main from app.main.views.pricing import CURRENT_SMS_RATE @@ -16,55 +20,42 @@ from app.main.views.sub_navigation_dictionaries import ( using_notify_nav, ) from app.utils.user import user_is_logged_in -from notifications_utils.url_safe_token import generate_token # Hook to check for feature flags @main.before_request def check_feature_flags(): - if ( - request.path.startswith("/guides/best-practices") - and not current_app.config.get("FEATURE_BEST_PRACTICES_ENABLED", False) + if request.path.startswith("/guides") and not current_app.config.get( + "FEATURE_BEST_PRACTICES_ENABLED", False ): abort(404) - if ( - request.path.startswith("/about") - and not current_app.config.get("FEATURE_ABOUT_PAGE_ENABLED", False) + if request.path.startswith("/about") and not current_app.config.get( + "FEATURE_ABOUT_PAGE_ENABLED", False ): abort(404) +@main.route("/test/feature-flags") +def test_feature_flags(): + return jsonify( + { + "FEATURE_BEST_PRACTICES_ENABLED": current_app.config[ + "FEATURE_BEST_PRACTICES_ENABLED" + ] + } + ) + + @main.route("/") def index(): if current_user and current_user.is_authenticated: return redirect(url_for("main.choose_account")) - ttl = 24 * 60 * 60 - - # make and store the state - state = generate_token( - str(request.remote_addr), - current_app.config["SECRET_KEY"], - current_app.config["DANGEROUS_SALT"], - ) - state_key = f"login-state-{unquote(state)}" - redis_client.set(state_key, state, ex=ttl) - - # make and store the nonce - nonce = secrets.token_urlsafe() - nonce_key = f"login-nonce-{unquote(nonce)}" - redis_client.set(nonce_key, nonce, ex=ttl) - - url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL") - if url is not None: - url = url.replace("NONCE", nonce) - url = url.replace("STATE", state) return render_template( "views/signedout.html", sms_rate=CURRENT_SMS_RATE, - counts=status_api_client.get_count_of_live_services_and_organizations(), - initial_signin_url=url, + counts=status_api_client.get_count_of_live_services_and_organizations() ) @@ -216,61 +207,61 @@ def trial_mode_new(): @user_is_logged_in def best_practices(): return render_template( - "views/best-practices/best-practices.html", + "views/guides/best-practices.html", navigation_links=best_practices_nav(), ) -@main.route("/guides/best-practices/clear-goals") +@main.route("/guides/clear-goals") @user_is_logged_in def clear_goals(): return render_template( - "views/best-practices/clear-goals.html", + "views/guides/clear-goals.html", navigation_links=best_practices_nav(), ) -@main.route("/guides/best-practices/rules-and-regulations") +@main.route("/guides/rules-and-regulations") @user_is_logged_in def rules_and_regulations(): return render_template( - "views/best-practices/rules-and-regulations.html", + "views/guides/rules-and-regulations.html", navigation_links=best_practices_nav(), ) -@main.route("/guides/best-practices/establish-trust") +@main.route("/guides/establish-trust") @user_is_logged_in def establish_trust(): return render_template( - "views/best-practices/establish-trust.html", + "views/guides/establish-trust.html", navigation_links=best_practices_nav(), ) -@main.route("/guides/best-practices/write-for-action") +@main.route("/guides/write-for-action") @user_is_logged_in def write_for_action(): return render_template( - "views/best-practices/write-for-action.html", + "views/guides/write-for-action.html", navigation_links=best_practices_nav(), ) -@main.route("/guides/best-practices/multiple-languages") +@main.route("/guides/multiple-languages") @user_is_logged_in def multiple_languages(): return render_template( - "views/best-practices/multiple-languages.html", + "views/guides/multiple-languages.html", navigation_links=best_practices_nav(), ) -@main.route("/guides/best-practices/benchmark-performance") +@main.route("/guides/benchmark-performance") @user_is_logged_in def benchmark_performance(): return render_template( - "views/best-practices/benchmark-performance.html", + "views/guides/benchmark-performance.html", navigation_links=best_practices_nav(), ) @@ -294,12 +285,26 @@ def about_notify(): navigation_links=about_notify_nav(), ) +@main.route("/about/security") +def about_security(): + return render_template( + "views/about/security.html", + navigation_links=about_notify_nav(), + ) + + +@main.route("/about/why-text-messaging") +def why_text_messaging(): + return render_template( + "views/about/why-text-messaging.html", + navigation_links=about_notify_nav(), + ) + @main.route("/about/join-notify") def join_notify(): return render_template( "views/about/join-notify.html", - navigation_links=about_notify_nav(), ) diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index 79c5c9be8..ec5f06169 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -1,3 +1,6 @@ +from flask import current_app + + def features_nav(): return [ { @@ -22,46 +25,20 @@ def features_nav(): def using_notify_nav(): - return [ - { - "name": "Get started", - "link": "main.get_started", - }, - { - "name": "Guides", - "link": "main.best_practices", - }, - { - "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", - # "sub_navigation_items": [ - # { - # "name": "Formatting", - # "link": "main.edit_and_format_messages", - # }, - # { - # "name": "Send files by email", - # "link": "main.send_files_by_email", - # }, - # ] - # { - # "name": "API documentation", - # "link": "main.documentation", - # }, - }, + nav_items = [ + {"name": "Get started", "link": "main.get_started"}, + {"name": "Guides", "link": "main.best_practices"}, + {"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"}, ] + if not current_app.config.get("FEATURE_BEST_PRACTICES_ENABLED"): + nav_items = [ + item for item in nav_items if item["link"] != "main.best_practices" + ] + + return nav_items def best_practices_nav(): @@ -110,8 +87,32 @@ def best_practices_nav(): def about_notify_nav(): return [ { - "name": "About notify", + "name": "About Notify", "link": "main.about_notify", + "sub_navigation_items": [ + { + "name": "Why text messaging", + "link": "main.why_text_messaging", + "sub_sub_navigation_items": [ + { + "name": "Reach people using a common method", + "link": "main.why_text_messaging#reach-people-using-a-common-method", + }, + { + "name": "Improve customer experience", + "link": "main.why_text_messaging#improve-customer-experience", + }, + { + "name": "What texting is best for", + "link": "main.why_text_messaging#what-texting-is-best-for", + }, + ], + }, + { + "name": "Security", + "link": "main.about_security", + }, + ], }, { "name": "Join Notify", diff --git a/app/navigation.py b/app/navigation.py index a02df484d..271d6848b 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -53,7 +53,7 @@ class HeaderNavigation(Navigation): "establish_trust", "write_for_action", "multiple_languages", - "benchmark_performance" + "benchmark_performance", }, "using_notify": { "get_started", diff --git a/app/templates/base.html b/app/templates/base.html index 369e62b81..b2b6639e9 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -66,7 +66,20 @@
diff --git a/app/templates/views/about/about.html b/app/templates/views/about/about.html
index 4fbae4951..bf4675602 100644
--- a/app/templates/views/about/about.html
+++ b/app/templates/views/about/about.html
@@ -1,13 +1,12 @@
{% extends "base.html" %}
-{% set page_title = "About notify" %}
+{% set page_title = "About Notify" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
-
Notify.gov is a text messaging service built by and for the government. We help agencies communicate more
@@ -17,8 +16,9 @@
Notify.gov is an easy-to-use, web-based platform. It requires no technical expertise or system integration — users
can create an account and get started within minutes. We take the security and privacy of messaging data seriously
@@ -68,10 +68,8 @@
{% endfor %}
- See if Notify is right for you Notify.gov is a product of the Public Benefits Studio, a product accelerator inside
+ See if Notify is right for you Notify.gov is a product of the Public Benefits Studio, a product accelerator inside
the federal government. Notify.gov is built for the needs of government agencies with fundamental system
+ security processes in place to:
+
+ Notify.gov operates under a full three-year Authority-to-Operate (ATO). This
+ federal security authorization process leverages security
+ controls provided by National Institute of Standards and Technology (NIST).
+
+ Our infrastructure runs on cloud.gov and utilizes several
+ services through Amazon Web
+ Services (AWS), including
+ AWS SNS for sending SMS
+ messages.
+ For more information about the Notify.gov infrastructure, contact us at notify-support@gsa.gov.
+ On Notify.gov, data is encrypted both in transit and at rest. To send a message, agencies upload a spreadsheet of
+ phone numbers and other necessary data from their existing data management system.
+
+ Notify.gov is not a system of record, so it does not have a System of Records Notice (SORN). Agencies are
+ responsible for managing their data outside of Notify.gov.
+
+ Any data uploads that have recipient data are held for seven calendar days; personally identifiable information
+ (PII) is never stored in Notify’s database.
+
+ Notify.gov uses Login.gov for enhanced security.
+ Login.gov is an extra layer of security created by the government that uses multi-factor authentication and stronger
+ passwords to protect your account.
+
+ To access Notify.gov, users will use a Login.gov account associated with their agency (.gov) email with one of the
+ multi-factor authentication
+ methods offered through Login.gov.
+
+ Confusing or unreceived notifications are one of the largest barriers to people getting and keeping
+ benefits. The typical ways the government communicates with people often fall short. Low income households are more
+ likely to experience housing instability, which means paper mail, already slow, can easily be missed.
+
+ Pew Research shows that nearly all adults in the US have a cell phone. Reliance on smartphones
+ for online access is especially common among Americans with lower household incomes and those with lower levels of
+ formal education. Of those earning less than $30,000 a year, 28% say their mobile phone is the sole method to
+ digitally connect.
+
+ This means that for many people who rely on government services, cell phones may be the most reliable place to meet
+ people where they already are.
+
+ Text messages can deliver concise information and drive an audience to take action quickly. Timely reminders sent
+ via text message have been proven to decrease re-enrollment churn and save money for administering agencies.
+
+ Texting not only helps programs reach people using a nearly-universal communication method, it is a cost effective
+ way to do so. With Notify.gov you can get started for free, allowing you to try out
+ texting to complement your existing communications and outreach strategies.
+
+ Agencies, like you, are already using Notify.gov to text about the following programs.
+ {{item.card_heading}} {{item.p_text}} Learn how effective your texting program can be.{{page_title}}
{{page_title}}
+
+
+ Data
+ Data retention
+ Multi-Factor Authentication
+ {{page_title}}
+ Reach people using a common method
+ Improve customer experience
+ What texting is best for
+
+ {% endif %}
+
{{page_title}}
- When the Center on Budget and Policy Priorities studied WIC, they found key learnings about the quantity of messages delivered, how people engage with messages, and how they take action. @@ -78,7 +80,8 @@
- The Code for America’s Texting
+ The Code for America’s Texting
Playbook
reported specific learnings around appointment reminders, completing
document submission, and maintenance reminders.
diff --git a/app/templates/views/best-practices/best-practices.html b/app/templates/views/guides/best-practices.html
similarity index 78%
rename from app/templates/views/best-practices/best-practices.html
rename to app/templates/views/guides/best-practices.html
index 7711dea9b..4784f72c4 100644
--- a/app/templates/views/best-practices/best-practices.html
+++ b/app/templates/views/guides/best-practices.html
@@ -1,11 +1,12 @@
{% extends "base.html" %}
+{% set page_title = "Best Practices" %}
+
{% block per_page_title %}
-Best Practices
+{{page_title}}
{% endblock %}
{% block content_column_content %}
-
For texting the public Start with a singular purpose. Make explicit what you want to achieve.Best Practices
{{page_title}}
Review your drafted hypothesis with your team to make sure everyone is aligned on your desired goals. A clear and - concise hypothesis can help you decide how to write text message + concise hypothesis can help you decide how to write text message content that provokes action.
diff --git a/app/templates/views/best-practices/establish-trust.html b/app/templates/views/guides/establish-trust.html similarity index 94% rename from app/templates/views/best-practices/establish-trust.html rename to app/templates/views/guides/establish-trust.html index fc26e2a71..3383315ba 100644 --- a/app/templates/views/best-practices/establish-trust.html +++ b/app/templates/views/guides/establish-trust.html @@ -1,5 +1,7 @@ {% extends "base.html" %} -{% from "components/best-practices/circle_number.html" import circle_number %} +{% import "components/nav_breadcrumb.html" as breadcrumbs %} + +{% from "components/guides/circle_number.html" import circle_number %} {% set page_title = "Establish trust" %} @@ -8,7 +10,8 @@ {% endblock %} {% block content_column_content %} -{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %} +{{ breadcrumbs.breadcrumb(page_title, "Guides", "main.best_practices") }} +Help your audience anticipate and welcome your texts.
@@ -38,7 +41,7 @@To reinforce legitimacy, include these key messages in your outreach:
-If you're sending one-way notifications, phone carriers allow a single auto-response message that will be generated if a recipient tries to text a response to your message. Use the auto-response to reaffirm your key messages around legitimacy and communicate to recipients that texts are coming from an automated system.
-What to know as you plan translated texts.
diff --git a/app/templates/views/best-practices/rules-and-regulations.html b/app/templates/views/guides/rules-and-regulations.html similarity index 94% rename from app/templates/views/best-practices/rules-and-regulations.html rename to app/templates/views/guides/rules-and-regulations.html index c9a95a122..db06ab76e 100644 --- a/app/templates/views/best-practices/rules-and-regulations.html +++ b/app/templates/views/guides/rules-and-regulations.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% import "components/nav_breadcrumb.html" as breadcrumbs %} {% set page_title = "Rules and regulations" %} @@ -7,7 +8,8 @@ {% endblock %} {% block content_column_content %} -{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %} +{{ breadcrumbs.breadcrumb(page_title, "Guides", "main.best_practices") }} +Understand what is required when texting the public.
@@ -20,7 +22,7 @@ If you do need expressed consent, consider including a pre-checked plain language opt-in (i.e. “It’s OK to text me.”) on digital forms. Be sure to ask for an up-to-date phone number and include a question about the recipient’s preferred - language for text messages if you expect to translate your text + language for text messages if you expect to translate your text messages in languages other than English. @@ -79,7 +81,7 @@There is no policy requirement for senders to communicate opt-out options, but including instructions in introductory and/or + href="../guides/establish-trust#as-people-receive-texts"> including instructions in introductory and/or auto-response texts on how to opt out and opt back in are effective ways to establish trust with your audience.
diff --git a/app/templates/views/best-practices/write-for-action.html b/app/templates/views/guides/write-for-action.html similarity index 90% rename from app/templates/views/best-practices/write-for-action.html rename to app/templates/views/guides/write-for-action.html index d97b74d8b..d3019596c 100644 --- a/app/templates/views/best-practices/write-for-action.html +++ b/app/templates/views/guides/write-for-action.html @@ -1,5 +1,6 @@ {% extends "base.html" %} -{% from "components/best-practices/circle_number.html" import circle_number %} +{% import "components/nav_breadcrumb.html" as breadcrumbs %} +{% from "components/guides/circle_number.html" import circle_number %} {% set page_title = "Write texts that provoke action" %} @@ -8,7 +9,8 @@ {% endblock %} {% block content_column_content %} -{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %} +{{ breadcrumbs.breadcrumb(page_title, "Guides", "main.best_practices") }} +Help your audience know what to do with the information you send.
@@ -40,11 +42,11 @@For example, getting a person to update their mailing address:
-Evidence
+ Evidence
shows that employing
behavioral science is an effective way to increase the
likelihood of a recipient
@@ -100,7 +103,7 @@
internet services that belong to you.",
},
] %}
- {% with card_contents=card_contents, text_align='left' %}{% include "components/best-practices/cards.html" %}{%
+ {% with card_contents=card_contents, text_align='left' %}{% include "components/guides/cards.html" %}{%
endwith %}
{% endblock %}
diff --git a/app/utils/csv.py b/app/utils/csv.py
index 4ed6d16b5..79e3535c8 100644
--- a/app/utils/csv.py
+++ b/app/utils/csv.py
@@ -103,6 +103,7 @@ def generate_notifications_csv(**kwargs):
"Carrier Response",
"Status",
"Time",
+ "Carrier",
]
for header in original_column_headers:
if header.lower() != "phone number":
@@ -118,6 +119,7 @@ def generate_notifications_csv(**kwargs):
"Carrier Response",
"Status",
"Time",
+ "Carrier",
]
yield ",".join(fieldnames) + "\n"
@@ -140,6 +142,7 @@ def generate_notifications_csv(**kwargs):
notification["provider_response"],
notification["status"],
preferred_tz_created_at,
+ notification["carrier"],
]
for header in original_column_headers:
if header.lower() != "phone number":
@@ -158,6 +161,7 @@ def generate_notifications_csv(**kwargs):
notification["provider_response"],
notification["status"],
preferred_tz_created_at,
+ notification["carrier"],
]
yield Spreadsheet.from_rows([map(str, values)]).as_csv_data
diff --git a/deploy-config/production.yml b/deploy-config/production.yml
index 42a681cb4..9f5cffc89 100644
--- a/deploy-config/production.yml
+++ b/deploy-config/production.yml
@@ -1,6 +1,6 @@
env: production
instances: 2
-memory: 1.5G
+memory: 2G
command: newrelic-admin run-program gunicorn -c /home/vcap/app/gunicorn_config.py application
public_admin_route: beta.notify.gov
cloud_dot_gov_route: notify.app.cloud.gov
diff --git a/package-lock.json b/package-lock.json
index 64db0c270..c6d584bcf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,7 @@
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/stream": "^3.0.1",
- "@uswds/uswds": "^3.9.0",
+ "@uswds/uswds": "^3.10.0",
"cbor-js": "0.1.0",
"d3": "^7.9.0",
"govuk_frontend_toolkit": "^9.0.1",
@@ -21,10 +21,10 @@
"hogan": "1.0.2",
"jquery": "3.7.1",
"morphdom": "^2.7.4",
- "playwright": "^1.48.2",
+ "playwright": "^1.49.0",
"python": "^0.0.4",
"query-command-supported": "1.0.0",
- "sass-embedded": "^1.80.6",
+ "sass-embedded": "^1.82.0",
"textarea-caret": "3.1.0",
"timeago": "1.6.7",
"vinyl-buffer": "^1.0.1",
@@ -50,7 +50,7 @@
"jest-environment-jsdom": "^29.2.2",
"jshint": "2.13.6",
"jshint-stylish": "2.2.1",
- "rollup": "^4.24.4",
+ "rollup": "^4.28.0",
"rollup-plugin-commonjs": "10.1.0",
"rollup-plugin-node-resolve": "5.2.0"
},
@@ -2667,216 +2667,234 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz",
- "integrity": "sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.0.tgz",
+ "integrity": "sha512-wLJuPLT6grGZsy34g4N1yRfYeouklTgPhH1gWXCYspenKYD0s3cR99ZevOGw5BexMNywkbV3UkjADisozBmpPQ==",
"cpu": [
"arm"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.4.tgz",
- "integrity": "sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.0.tgz",
+ "integrity": "sha512-eiNkznlo0dLmVG/6wf+Ifi/v78G4d4QxRhuUl+s8EWZpDewgk7PX3ZyECUXU0Zq/Ca+8nU8cQpNC4Xgn2gFNDA==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz",
- "integrity": "sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.0.tgz",
+ "integrity": "sha512-lmKx9yHsppblnLQZOGxdO66gT77bvdBtr/0P+TPOseowE7D9AJoBw8ZDULRasXRWf1Z86/gcOdpBrV6VDUY36Q==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.4.tgz",
- "integrity": "sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.0.tgz",
+ "integrity": "sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.4.tgz",
- "integrity": "sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.0.tgz",
+ "integrity": "sha512-lA1zZB3bFx5oxu9fYud4+g1mt+lYXCoch0M0V/xhqLoGatbzVse0wlSQ1UYOWKpuSu3gyN4qEc0Dxf/DII1bhQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.4.tgz",
- "integrity": "sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.0.tgz",
+ "integrity": "sha512-aI2plavbUDjCQB/sRbeUZWX9qp12GfYkYSJOrdYTL/C5D53bsE2/nBPuoiJKoWp5SN78v2Vr8ZPnB+/VbQ2pFA==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.4.tgz",
- "integrity": "sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.0.tgz",
+ "integrity": "sha512-WXveUPKtfqtaNvpf0iOb0M6xC64GzUX/OowbqfiCSXTdi/jLlOmH0Ba94/OkiY2yTGTwteo4/dsHRfh5bDCZ+w==",
"cpu": [
"arm"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.4.tgz",
- "integrity": "sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.0.tgz",
+ "integrity": "sha512-yLc3O2NtOQR67lI79zsSc7lk31xjwcaocvdD1twL64PK1yNaIqCeWI9L5B4MFPAVGEVjH5k1oWSGuYX1Wutxpg==",
"cpu": [
"arm"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.4.tgz",
- "integrity": "sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.0.tgz",
+ "integrity": "sha512-+P9G9hjEpHucHRXqesY+3X9hD2wh0iNnJXX/QhS/J5vTdG6VhNYMxJ2rJkQOxRUd17u5mbMLHM7yWGZdAASfcg==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.4.tgz",
- "integrity": "sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.0.tgz",
+ "integrity": "sha512-1xsm2rCKSTpKzi5/ypT5wfc+4bOGa/9yI/eaOLW0oMs7qpC542APWhl4A37AENGZ6St6GBMWhCCMM6tXgTIplw==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.4.tgz",
- "integrity": "sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.0.tgz",
+ "integrity": "sha512-zgWxMq8neVQeXL+ouSf6S7DoNeo6EPgi1eeqHXVKQxqPy1B2NvTbaOUWPn/7CfMKL7xvhV0/+fq/Z/J69g1WAQ==",
"cpu": [
"ppc64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.4.tgz",
- "integrity": "sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.0.tgz",
+ "integrity": "sha512-VEdVYacLniRxbRJLNtzwGt5vwS0ycYshofI7cWAfj7Vg5asqj+pt+Q6x4n+AONSZW/kVm+5nklde0qs2EUwU2g==",
"cpu": [
"riscv64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.4.tgz",
- "integrity": "sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.0.tgz",
+ "integrity": "sha512-LQlP5t2hcDJh8HV8RELD9/xlYtEzJkm/aWGsauvdO2ulfl3QYRjqrKW+mGAIWP5kdNCBheqqqYIGElSRCaXfpw==",
"cpu": [
"s390x"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.4.tgz",
- "integrity": "sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.0.tgz",
+ "integrity": "sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.4.tgz",
- "integrity": "sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.0.tgz",
+ "integrity": "sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.4.tgz",
- "integrity": "sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.0.tgz",
+ "integrity": "sha512-Vi+WR62xWGsE/Oj+mD0FNAPY2MEox3cfyG0zLpotZdehPFXwz6lypkGs5y38Jd/NVSbOD02aVad6q6QYF7i8Bg==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.4.tgz",
- "integrity": "sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.0.tgz",
+ "integrity": "sha512-kN/Vpip8emMLn/eOza+4JwqDZBL6MPNpkdaEsgUtW1NYN3DZvZqSQrbKzJcTL6hd8YNmFTn7XGWMwccOcJBL0A==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.4.tgz",
- "integrity": "sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.0.tgz",
+ "integrity": "sha512-Bvno2/aZT6usSa7lRDL2+hMjVAGjuqaymF1ApZm31JXzniR/hvr14jpU+/z4X6Gt5BPlzosscyJZGUvguXIqeQ==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -3485,11 +3503,10 @@
}
},
"node_modules/@uswds/uswds": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/@uswds/uswds/-/uswds-3.9.0.tgz",
- "integrity": "sha512-8THm36j7iLjrDiI1D0C6b3hHsmM/Sy5Iiz+IjE+i/gYzVUMG9XVthxAZYonhU97Q1b079n6nYwlUmDSYowJecQ==",
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/@uswds/uswds/-/uswds-3.10.0.tgz",
+ "integrity": "sha512-LWFTQzp4e3kqtnD/Wsyfx9uGTkn5GEpzhscNWJMIsdWBGKtiu96QT99oRJUmcsB6HbGhR0Th0FtlK/Zzx2WghA==",
"dependencies": {
- "object-assign": "4.1.1",
"receptor": "1.0.0",
"resolve-id-refs": "0.1.0"
},
@@ -5146,10 +5163,11 @@
}
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -8314,7 +8332,8 @@
"node_modules/immutable": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz",
- "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ=="
+ "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==",
+ "dev": true
},
"node_modules/import-fresh": {
"version": "3.3.0",
@@ -12011,11 +12030,11 @@
}
},
"node_modules/playwright": {
- "version": "1.48.2",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz",
- "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz",
+ "integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==",
"dependencies": {
- "playwright-core": "1.48.2"
+ "playwright-core": "1.49.0"
},
"bin": {
"playwright": "cli.js"
@@ -12028,9 +12047,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.48.2",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz",
- "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==",
+ "version": "1.49.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz",
+ "integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==",
"bin": {
"playwright-core": "cli.js"
},
@@ -12951,9 +12970,10 @@
"license": "Unlicense"
},
"node_modules/rollup": {
- "version": "4.24.4",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.4.tgz",
- "integrity": "sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==",
+ "version": "4.28.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.0.tgz",
+ "integrity": "sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==",
+ "license": "MIT",
"dependencies": {
"@types/estree": "1.0.6"
},
@@ -12965,24 +12985,24 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.24.4",
- "@rollup/rollup-android-arm64": "4.24.4",
- "@rollup/rollup-darwin-arm64": "4.24.4",
- "@rollup/rollup-darwin-x64": "4.24.4",
- "@rollup/rollup-freebsd-arm64": "4.24.4",
- "@rollup/rollup-freebsd-x64": "4.24.4",
- "@rollup/rollup-linux-arm-gnueabihf": "4.24.4",
- "@rollup/rollup-linux-arm-musleabihf": "4.24.4",
- "@rollup/rollup-linux-arm64-gnu": "4.24.4",
- "@rollup/rollup-linux-arm64-musl": "4.24.4",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.24.4",
- "@rollup/rollup-linux-riscv64-gnu": "4.24.4",
- "@rollup/rollup-linux-s390x-gnu": "4.24.4",
- "@rollup/rollup-linux-x64-gnu": "4.24.4",
- "@rollup/rollup-linux-x64-musl": "4.24.4",
- "@rollup/rollup-win32-arm64-msvc": "4.24.4",
- "@rollup/rollup-win32-ia32-msvc": "4.24.4",
- "@rollup/rollup-win32-x64-msvc": "4.24.4",
+ "@rollup/rollup-android-arm-eabi": "4.28.0",
+ "@rollup/rollup-android-arm64": "4.28.0",
+ "@rollup/rollup-darwin-arm64": "4.28.0",
+ "@rollup/rollup-darwin-x64": "4.28.0",
+ "@rollup/rollup-freebsd-arm64": "4.28.0",
+ "@rollup/rollup-freebsd-x64": "4.28.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.28.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.28.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.28.0",
+ "@rollup/rollup-linux-arm64-musl": "4.28.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.28.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.28.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.28.0",
+ "@rollup/rollup-linux-x64-gnu": "4.28.0",
+ "@rollup/rollup-linux-x64-musl": "4.28.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.28.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.28.0",
+ "@rollup/rollup-win32-x64-msvc": "4.28.0",
"fsevents": "~2.3.2"
}
},
@@ -13091,16 +13111,18 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sass-embedded": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.80.6.tgz",
- "integrity": "sha512-Og4aqBnaA3oJfIpHaLuNATAqzBRgUJDYJy2X15V59cot2wYOtiT/ciPnyuq1o7vpDEeOkHhEd+mSviSlXoETug==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.82.0.tgz",
+ "integrity": "sha512-v13sRVVZtWAQLpAGTz5D8hy+oyNKRHao5tKVc/P6AMqSP+jDM8X6GkEpL0jfbu3MaN2/hAQsd4Qx14GG1u0prQ==",
+ "license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.0.0",
"buffer-builder": "^0.2.0",
"colorjs.io": "^0.5.0",
- "immutable": "^4.0.0",
+ "immutable": "^5.0.2",
"rxjs": "^7.4.0",
"supports-color": "^8.1.1",
+ "sync-child-process": "^1.0.2",
"varint": "^6.0.0"
},
"bin": {
@@ -13110,35 +13132,36 @@
"node": ">=16.0.0"
},
"optionalDependencies": {
- "sass-embedded-android-arm": "1.80.6",
- "sass-embedded-android-arm64": "1.80.6",
- "sass-embedded-android-ia32": "1.80.6",
- "sass-embedded-android-riscv64": "1.80.6",
- "sass-embedded-android-x64": "1.80.6",
- "sass-embedded-darwin-arm64": "1.80.6",
- "sass-embedded-darwin-x64": "1.80.6",
- "sass-embedded-linux-arm": "1.80.6",
- "sass-embedded-linux-arm64": "1.80.6",
- "sass-embedded-linux-ia32": "1.80.6",
- "sass-embedded-linux-musl-arm": "1.80.6",
- "sass-embedded-linux-musl-arm64": "1.80.6",
- "sass-embedded-linux-musl-ia32": "1.80.6",
- "sass-embedded-linux-musl-riscv64": "1.80.6",
- "sass-embedded-linux-musl-x64": "1.80.6",
- "sass-embedded-linux-riscv64": "1.80.6",
- "sass-embedded-linux-x64": "1.80.6",
- "sass-embedded-win32-arm64": "1.80.6",
- "sass-embedded-win32-ia32": "1.80.6",
- "sass-embedded-win32-x64": "1.80.6"
+ "sass-embedded-android-arm": "1.82.0",
+ "sass-embedded-android-arm64": "1.82.0",
+ "sass-embedded-android-ia32": "1.82.0",
+ "sass-embedded-android-riscv64": "1.82.0",
+ "sass-embedded-android-x64": "1.82.0",
+ "sass-embedded-darwin-arm64": "1.82.0",
+ "sass-embedded-darwin-x64": "1.82.0",
+ "sass-embedded-linux-arm": "1.82.0",
+ "sass-embedded-linux-arm64": "1.82.0",
+ "sass-embedded-linux-ia32": "1.82.0",
+ "sass-embedded-linux-musl-arm": "1.82.0",
+ "sass-embedded-linux-musl-arm64": "1.82.0",
+ "sass-embedded-linux-musl-ia32": "1.82.0",
+ "sass-embedded-linux-musl-riscv64": "1.82.0",
+ "sass-embedded-linux-musl-x64": "1.82.0",
+ "sass-embedded-linux-riscv64": "1.82.0",
+ "sass-embedded-linux-x64": "1.82.0",
+ "sass-embedded-win32-arm64": "1.82.0",
+ "sass-embedded-win32-ia32": "1.82.0",
+ "sass-embedded-win32-x64": "1.82.0"
}
},
"node_modules/sass-embedded-android-arm": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.80.6.tgz",
- "integrity": "sha512-UeUKMTRsnz4/dh7IzvhjONxa4/jmVp539CHDd8VZOsqg9M3HcNJNIkUzQWbuwZ+nSlWrTuo7Tvn3XlypopCBzw==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.82.0.tgz",
+ "integrity": "sha512-ttGMvWnA/5TYdZTjr5fWHDbb9nZgKipHKCc9zZQRF5HjUydOYWKNqmAJHQtbFWaq35kd5qn6yiE73IJN6eJ6wA==",
"cpu": [
"arm"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -13148,12 +13171,13 @@
}
},
"node_modules/sass-embedded-android-arm64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.80.6.tgz",
- "integrity": "sha512-4rC4ZGM/k4ENVjLXnK3JTst8e8FI9MHSol2Fl7dCdYyJ3KLnlt4qL4AEYfU8zq1tcBb7CBOSZVR+CzCKubnXdg==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.82.0.tgz",
+ "integrity": "sha512-bldHMs02QQWXsgHUZRgolNnZdMjN6XHvmUYoRkzmFq7lsvtLU6SJg2S1Wa9IZJs9jRWdTmOgA6YibSf3pROyFQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -13163,12 +13187,13 @@
}
},
"node_modules/sass-embedded-android-ia32": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.80.6.tgz",
- "integrity": "sha512-Lxz2SXE2KdHnynuHF+D6flDvrd55/zaEAWUeka9MxEr6FmR66d8UBOIy5ETwCSUd//S/SE5Jl6oTnHppgD1zNA==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.82.0.tgz",
+ "integrity": "sha512-FUJOnxw8IYKuYuxxiOkk6QXle8/yQFtKjnuSAJuZ5ZpLVMcSZzLc3SWOtuEXYx5iSAfJCO075o2ZoG/pPrJ9aw==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -13178,12 +13203,13 @@
}
},
"node_modules/sass-embedded-android-riscv64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.80.6.tgz",
- "integrity": "sha512-hKdxY/oOqB+JJhSoBTDM5DJO1j/xtxQgayh2cLCCUx37IQQe3SEdc3V2JFf/4mIo5peaS4cjqwwSATF+l2zaXg==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.82.0.tgz",
+ "integrity": "sha512-rd+vc+sxJxNnbhaubiIJmnb1b3FvC9wxCIq8spstopbO7o1uufvBBDeRoFSJaN+7oNhamzjlYGdu6aQoQNs3+A==",
"cpu": [
"riscv64"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -13193,12 +13219,13 @@
}
},
"node_modules/sass-embedded-android-x64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.80.6.tgz",
- "integrity": "sha512-Eap2Fi3kTx/rVLBsOnOp5RYPr5+lFjTZ652zR24dmYFe9/sDgasakJIOPjOvD2bRuL9z0uWEY1AXVeeOPeZKrg==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.82.0.tgz",
+ "integrity": "sha512-EVlybGTgJ8wNLyWj8RUatPXSnmIcvCsx3EfsRfBfhGihLbn4NNpavYO9QsvZzI2XWbJqHLBCd+CvkTcDw/TaSQ==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -13208,12 +13235,13 @@
}
},
"node_modules/sass-embedded-darwin-arm64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.80.6.tgz",
- "integrity": "sha512-0mnAx8Vq6Gxj3PQt3imgITfK33hhqrSKpyHSuab71gZZni5opsdtoggq2JawW+1taRFTEZwbZJLKZ0MBDbwCCA==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.82.0.tgz",
+ "integrity": "sha512-LvdJPojjKlNGYOB0nSUR/ZtMDuAF4puspHlwK42aA/qK292bfSkMUKZPPapB2aSRwccc/ieBq5fI7n/WHrOCVw==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -13223,12 +13251,13 @@
}
},
"node_modules/sass-embedded-darwin-x64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.80.6.tgz",
- "integrity": "sha512-Ib20yNZFOrJ7YVT+ltoe+JQNKPcRclM3iLAK69XZZYcSeFM/72SCoQBAaVGIpT23dxDp7FXiE4lO602c3xTRwQ==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.82.0.tgz",
+ "integrity": "sha512-6LfnD6YmG1aBfd3ReqMOJDb6Pg2Z/hmlJB7nU+Lb3E+hCNjAZAgeUHQxU/Pm1eIqJJTU/h4ib5QP0Pt9O8yVnw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -13238,12 +13267,13 @@
}
},
"node_modules/sass-embedded-linux-arm": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.80.6.tgz",
- "integrity": "sha512-QR0Q6TZox/ThuU2r9c0s3fKCgU2rXAEocpitdgxFp6tta+GsQlMFV3oON2unAa8Bwnuxkmf0YOaK0Oy/TwzkXw==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.82.0.tgz",
+ "integrity": "sha512-ozjdC5rWzyi5Vo300I4tVZzneXOTQUiaxOr7DjtN26HuFaGAGCGmvThh2BRV4RvySg++5H9rdFu+VgyUQ5iukw==",
"cpu": [
"arm"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13253,12 +13283,13 @@
}
},
"node_modules/sass-embedded-linux-arm64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.80.6.tgz",
- "integrity": "sha512-n5r98pBXawrQQKaxIYCMM1zDpnngsqxTkOrmvsYLFiAMCSbR0lWf/7sBB33k/Pm0D6dsbp3jpHilCoQNKI3jIw==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.82.0.tgz",
+ "integrity": "sha512-590/y0HJr/JiyxaqgR7Xf9P20BIhJ+zhB/afAnVuZe/4lEfCpTyM5xMe2+sKLsqtrVyzs9Zm/M4S4ASUOPCggA==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13268,12 +13299,13 @@
}
},
"node_modules/sass-embedded-linux-ia32": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.80.6.tgz",
- "integrity": "sha512-O6dWZdcOkryRdDCxVMGOeVowgblpDgVcAuRtZ1F1X7XfbpDriTQm64D+9vVZIrywYSPoJfQMJJ662cr0wUs9IQ==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.82.0.tgz",
+ "integrity": "sha512-hpc4acZ3UTjjJ3Q/GUXqQOCSml6AFKaku0HMawra9bKyRmOpxn8V5hqgXeOWVjK2oQzCmCnJvwKoQUP+S/SIYQ==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13283,12 +13315,13 @@
}
},
"node_modules/sass-embedded-linux-musl-arm": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.80.6.tgz",
- "integrity": "sha512-X9FC8s8fvQGRiXc+eATlZ57N44Iq3nNa0M0ugi3ysdJwkaNYvOeS4QzBHKQAaw3QiTqdxTnLUHHVBkyzdCi9pw==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.82.0.tgz",
+ "integrity": "sha512-R5PQmY/I+GSoMtfLo8GgHkvF/q6x6y8VNM7yu/Ac1mJj86n48VFi29W1HfY2496+Q6cpAq7toobDj7YfldIdVA==",
"cpu": [
"arm"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13298,12 +13331,13 @@
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.80.6.tgz",
- "integrity": "sha512-VeUSHUi3MAsvOlg9QI4X/2j04h1659aE+7qKP/282CYBTrGkjFGSXZhIki9WKWDgIpDiSInRYXfQQRWhPhjCDg==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.82.0.tgz",
+ "integrity": "sha512-bc2MUSMv/jabnNGEyKP2jQAYZoEzTT/c633W6QoeSEWETGCuTNjaHvWWE6qSI6/UfRg1EpuV1LQA2jPMzZfv/w==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13313,12 +13347,13 @@
}
},
"node_modules/sass-embedded-linux-musl-ia32": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.80.6.tgz",
- "integrity": "sha512-GqitS2Nab8ah0+wfCqaxW1hnI1piC08FimL6+lM9YWK5DbCOOF82IapbvJOy0feUmd/wNnHmyNTgE9h0zVMFdQ==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.82.0.tgz",
+ "integrity": "sha512-ZQKCFKm5TBcJ19UG6uUQmIKfVCJIWMb7e1a93lGeujSb9gyKF5Fb6MN3tuExoT7iFK8zU0Z9iyHqh93F58lcCw==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13328,12 +13363,13 @@
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.80.6.tgz",
- "integrity": "sha512-ySs15z7QSRRQK/aByEEqaJLYW/sTpfynefNPZCtsVNVEzNRwy+DRpxNChtxo+QjKq97ocXETbdG5KLik7QOTJg==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.82.0.tgz",
+ "integrity": "sha512-5meSU8BHFeaT09RWfkuUrikRlC+WZcYb9To7MpfV1d9nlD7CZ2xydPExK+mj3DqRuQvTbvhMPcr7f+pHlgHINQ==",
"cpu": [
"riscv64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13343,12 +13379,13 @@
}
},
"node_modules/sass-embedded-linux-musl-x64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.80.6.tgz",
- "integrity": "sha512-DzeNqU/SN0mWFznoOH4RtVGcrg3Eoa41pUQhKMtrhNbCmIE1zNDunUiAEVTNpdHJF4nxf7ELUPXWmStM31CbUQ==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.82.0.tgz",
+ "integrity": "sha512-ASLAMfjWv7YEPBvEOVlb3zzHq8l4Y9Eh4x3m7B1dNauGVbO11Yng5cPCX/XbwGVf30BtE75pwqvV7oXxBtN15w==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13358,12 +13395,13 @@
}
},
"node_modules/sass-embedded-linux-riscv64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.80.6.tgz",
- "integrity": "sha512-AyoHJ3icV9xuJjq1YzJqpEj2XfiC/KBkVYTUrCELKiXP0DN1gi/BpUwZNCAgCM3CyEdMef4LQM/ztCYJxYzdyg==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.82.0.tgz",
+ "integrity": "sha512-qWvRDXCXH3GzD8OcP0ntd8gBTK3kZyUeyXmxQDZyEtMAM4STC2Tn7+5+2JYYHlppzqWnZPFBNESvpKeOtHaBBw==",
"cpu": [
"riscv64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13373,12 +13411,13 @@
}
},
"node_modules/sass-embedded-linux-x64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.80.6.tgz",
- "integrity": "sha512-EohsE9CEqx0ycylnsEj/0DNPG99Tb0qAVZspiAs5xHFCJjXOFfp3cRQu0BRf+lZ1b72IhPFXymzVtojvzUHb7g==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.82.0.tgz",
+ "integrity": "sha512-AmRaHqShztwfep+M4NagdGaY7fTyWGSOM3k4Z/dd7q4nZclXbALLqNJtKx8xOM7A41LHYJ9zDpIBVRkrh0PzTA==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -13388,12 +13427,13 @@
}
},
"node_modules/sass-embedded-win32-arm64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.80.6.tgz",
- "integrity": "sha512-29wETQi1ykeVvpd4zMVokpQKFSOZskGJzZawuuNCdo7BHjHKIRDsqbz8YT1CewHPBshI0hfD21fenmjxYjGXPQ==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.82.0.tgz",
+ "integrity": "sha512-zL9JDQZHXHSGAZe5DqSrR86wMHbm9QPziU4/3hoIG+99StuS74CuV42+hw/+FXXBkXMWbjKWsyF/HZt+I/wJuw==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -13403,12 +13443,13 @@
}
},
"node_modules/sass-embedded-win32-ia32": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.80.6.tgz",
- "integrity": "sha512-1s3OpK2iTIfIL/a91QhAQnffsbuWfnsM8Lx4Fxt0f7ErnxjCV6q8MUFTV/UhcLtLyTFnPCA62DLjp2KGCjMI9A==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.82.0.tgz",
+ "integrity": "sha512-xE+AzLquCkFPnnpo0NHjQdLRIhG1bVs42xIKx42aUbVLYKkBDvbBGpw6EtTscRMyvcjoOqGH5saRvSFComUQcw==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -13418,12 +13459,13 @@
}
},
"node_modules/sass-embedded-win32-x64": {
- "version": "1.80.6",
- "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.80.6.tgz",
- "integrity": "sha512-0pH4Zr9silHkcmLPC0ghnD3DI0vMsjA7dKvGR32/RbbjOSvHV5cDQRLiuVJAPp34dfMA7kJd1ysSchRdH0igAQ==",
+ "version": "1.82.0",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.82.0.tgz",
+ "integrity": "sha512-cEgfOQG5womOzzk16ReTv2dxPq5BG16LgLUold/LH9IZH86u4E/MN7Fspf4RWeEJ2EcLdew9QYSC2YWs1l98dQ==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -13445,6 +13487,11 @@
"node": ">=8"
}
},
+ "node_modules/sass-embedded/node_modules/immutable": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz",
+ "integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw=="
+ },
"node_modules/sass-embedded/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -13994,6 +14041,25 @@
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"dev": true
},
+ "node_modules/sync-child-process": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
+ "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
+ "dependencies": {
+ "sync-message-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/sync-message-port": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz",
+ "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/table": {
"version": "6.8.2",
"resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
diff --git a/package.json b/package.json
index ae76a1849..3d61d5b71 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/stream": "^3.0.1",
- "@uswds/uswds": "^3.9.0",
+ "@uswds/uswds": "^3.10.0",
"cbor-js": "0.1.0",
"d3": "^7.9.0",
"govuk_frontend_toolkit": "^9.0.1",
@@ -37,10 +37,10 @@
"hogan": "1.0.2",
"jquery": "3.7.1",
"morphdom": "^2.7.4",
- "playwright": "^1.48.2",
+ "playwright": "^1.49.0",
"python": "^0.0.4",
"query-command-supported": "1.0.0",
- "sass-embedded": "^1.80.6",
+ "sass-embedded": "^1.82.0",
"textarea-caret": "3.1.0",
"timeago": "1.6.7",
"vinyl-buffer": "^1.0.1",
@@ -66,7 +66,7 @@
"jest-environment-jsdom": "^29.2.2",
"jshint": "2.13.6",
"jshint-stylish": "2.2.1",
- "rollup": "^4.24.4",
+ "rollup": "^4.28.0",
"rollup-plugin-commonjs": "10.1.0",
"rollup-plugin-node-resolve": "5.2.0"
}
diff --git a/poetry.lock b/poetry.lock
index 160d4c831..aff07625d 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
[[package]]
name = "ago"
@@ -1616,18 +1616,18 @@ files = [
[[package]]
name = "moto"
-version = "5.0.18"
+version = "5.0.22"
description = ""
optional = false
python-versions = ">=3.8"
files = [
- {file = "moto-5.0.18-py2.py3-none-any.whl", hash = "sha256:8e25401f7d7910e19a732b417e0d503ef86cf4de9114a273dd62679a42f3be1c"},
- {file = "moto-5.0.18.tar.gz", hash = "sha256:8a7ad2f53a2e6cc9db2ff65c0e0d4b5d7e78bc00b825c9e1ff6cc394371e76e9"},
+ {file = "moto-5.0.22-py3-none-any.whl", hash = "sha256:defae32e834ba5674f77cbbe996b41dc248dd81289af8032fa3e847284409b29"},
+ {file = "moto-5.0.22.tar.gz", hash = "sha256:daf47b8a1f5f190cd3eaa40018a643f38e542277900cf1db7f252cedbfed998f"},
]
[package.dependencies]
boto3 = ">=1.9.201"
-botocore = ">=1.14.0"
+botocore = ">=1.14.0,<1.35.45 || >1.35.45,<1.35.46 || >1.35.46"
cryptography = ">=3.3.1"
Jinja2 = ">=2.10.1"
python-dateutil = ">=2.1,<3.0.0"
diff --git a/tests/app/main/views/test_index.py b/tests/app/main/views/test_index.py
index 27e7f074e..e32ca11ea 100644
--- a/tests/app/main/views/test_index.py
+++ b/tests/app/main/views/test_index.py
@@ -125,6 +125,7 @@ def test_static_pages(client_request, mock_get_organization_by_domain, view, moc
"write_for_action",
"multiple_languages",
"benchmark_performance",
+ "guidance_index"
]
return (
not current_app.config["FEATURE_BEST_PRACTICES_ENABLED"]
diff --git a/tests/app/test_navigation.py b/tests/app/test_navigation.py
index 98a47de54..8999509b5 100644
--- a/tests/app/test_navigation.py
+++ b/tests/app/test_navigation.py
@@ -18,6 +18,7 @@ EXCLUDED_ENDPOINTS = tuple(
Navigation.get_endpoint_with_blueprint,
{
"about_notify",
+ "about_security",
"accept_invite",
"accept_org_invite",
"accessibility_statement",
@@ -219,6 +220,7 @@ EXCLUDED_ENDPOINTS = tuple(
"suspend_service",
"template_history",
"template_usage",
+ "test_feature_flags",
"tour_step",
"trial_mode",
"trial_mode_new",
@@ -258,6 +260,7 @@ EXCLUDED_ENDPOINTS = tuple(
"view_template_version",
"view_template_versions",
"who_its_for",
+ "why_text_messaging",
"write_for_action",
},
)
diff --git a/tests/app/utils/test_csv.py b/tests/app/utils/test_csv.py
index d603fcd0e..db4b6a0ec 100644
--- a/tests/app/utils/test_csv.py
+++ b/tests/app/utils/test_csv.py
@@ -58,6 +58,7 @@ def _get_notifications_csv(
"to": recipient,
"recipient": recipient,
"client_reference": "ref 1234",
+ "carrier": "AT&T Mobility",
}
for i in range(rows)
],
@@ -88,15 +89,15 @@ def get_notifications_csv_mock(
(
None,
[
- "Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time\n",
- "8005555555,foo,,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern\r\n",
+ "Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time,Carrier\n",
+ "8005555555,foo,,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern,AT&T Mobility\r\n",
],
),
(
"Anne Example",
[
- "Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time\n",
- "8005555555,foo,Anne Example,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern\r\n", # noqa
+ "Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time,Carrier\n",
+ "8005555555,foo,Anne Example,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern,AT&T Mobility\r\n", # noqa
],
),
],
@@ -135,6 +136,7 @@ def test_generate_notifications_csv_without_job(
"Carrier Response",
"Status",
"Time",
+ "Carrier",
],
[
"8005555555",
@@ -144,6 +146,7 @@ def test_generate_notifications_csv_without_job(
"Did not like it",
"Delivered",
"1943-04-19 08:00:00 AM US/Eastern",
+ "AT&T Mobility",
],
),
(
@@ -159,6 +162,7 @@ def test_generate_notifications_csv_without_job(
"Carrier Response",
"Status",
"Time",
+ "Carrier",
"a",
"b",
"c",
@@ -171,6 +175,7 @@ def test_generate_notifications_csv_without_job(
"Did not like it",
"Delivered",
"1943-04-19 08:00:00 AM US/Eastern",
+ "AT&T Mobility",
"🐜",
"🐝",
"🦀",
@@ -189,6 +194,7 @@ def test_generate_notifications_csv_without_job(
"Carrier Response",
"Status",
"Time",
+ "Carrier",
"a",
"b",
"c",
@@ -201,6 +207,7 @@ def test_generate_notifications_csv_without_job(
"Did not like it",
"Delivered",
"1943-04-19 08:00:00 AM US/Eastern",
+ "AT&T Mobility",
"🐜,🐜",
"🐝,🐝",
"🦀",
diff --git a/tests/end_to_end/test_best_practices_content_pages.py b/tests/end_to_end/test_best_practices_content_pages.py
new file mode 100644
index 000000000..5a75f9694
--- /dev/null
+++ b/tests/end_to_end/test_best_practices_content_pages.py
@@ -0,0 +1,72 @@
+import os
+import re
+
+from playwright.sync_api import expect
+
+from tests.end_to_end.conftest import check_axe_report
+
+E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
+
+
+def test_best_practices_side_menu(authenticated_page):
+ page = authenticated_page
+
+ page.goto(f"{E2E_TEST_URI}")
+
+ page.wait_for_load_state("domcontentloaded")
+ check_axe_report(page)
+
+ response = page.request.get(f"{E2E_TEST_URI}/test/feature-flags")
+ feature_flags = response.json()
+ feature_best_practices_enabled = feature_flags.get("FEATURE_BEST_PRACTICES_ENABLED")
+
+ if feature_best_practices_enabled:
+ page.get_by_role("link", name="Best Practices").click()
+ expect(page).to_have_title(re.compile("Best Practice"))
+
+ page.get_by_role("link", name="Clear goals", exact=True).click()
+ expect(page).to_have_title(re.compile("Establish clear goals"))
+
+ page.get_by_role("link", name="Rules and regulations").click()
+ expect(page).to_have_title(re.compile("Rules and regulations"))
+
+ page.get_by_role("link", name="Establish trust").click()
+ expect(page).to_have_title(re.compile("Establish trust"))
+
+ page.get_by_role("link", name="Write for action").click()
+ expect(page).to_have_title(re.compile("Write texts that provoke"))
+
+ page.get_by_role("link", name="Multiple languages").click()
+ expect(page).to_have_title(re.compile("Text in multiple languages"))
+
+ page.get_by_role("link", name="Benchmark performance").click()
+ expect(page).to_have_title(re.compile("Measuring performance with"))
+
+ parent_link = page.get_by_role("link", name="Establish trust")
+ parent_link.hover()
+
+ submenu_item = page.get_by_role("link", name=re.compile("Get the word out"))
+ submenu_item.click()
+
+ expect(page).to_have_url(re.compile(r"#get-the-word-out"))
+
+ anchor_target = page.locator("#get-the-word-out")
+ expect(anchor_target).to_be_visible()
+ anchor_target.click()
+
+
+def test_breadcrumbs_best_practices(authenticated_page):
+ page = authenticated_page
+
+ page.goto(f"{E2E_TEST_URI}")
+
+ page.wait_for_load_state("domcontentloaded")
+ check_axe_report(page)
+
+ response = page.request.get(f"{E2E_TEST_URI}/test/feature-flags")
+ feature_flags = response.json()
+ feature_best_practices_enabled = feature_flags.get("FEATURE_BEST_PRACTICES_ENABLED")
+
+ if feature_best_practices_enabled:
+ page.get_by_role("link", name="Clear goals", exact=True).click()
+ page.locator("ol").get_by_role("link", name="Best Practices").click()
diff --git a/urls.js b/urls.js
index 0440430ec..bd693cc90 100644
--- a/urls.js
+++ b/urls.js
@@ -8,29 +8,29 @@ const sublinks = [
{ label: 'Trial Mode', path: '/using-notify/trial-mode' },
{ label: 'Pricing', path: '/using-notify/pricing' },
{ label: 'Delivery Status', path: '/using-notify/delivery-status' },
- { label: 'Guidance', path: '/using-notify/guidance' },
+ { label: 'Guidance', path: '/guides/using-notify/guidance' },
{ label: 'Features', path: '/features' },
{ label: 'Roadmap', path: '/features/roadmap' },
{ label: 'Security', path: '/features/security' },
{ label: 'Support', path: '/support' },
{ label: 'Best Practices', path: '/guides/best-practices' },
- { label: 'Clear Goals', path: '/guides/best-practices/clear-goals' },
+ { label: 'Clear Goals', path: '/guides/clear-goals' },
{
label: 'Rules And Regulations',
- path: '/guides/best-practices/rules-and-regulations',
+ path: '/guides/rules-and-regulations',
},
- { label: 'Establish Trust', path: '/guides/best-practices/establish-trust' },
+ { label: 'Establish Trust', path: '/guides/establish-trust' },
{
label: 'Write For Action',
- path: '/guides/best-practices/write-for-action',
+ path: '/guides/write-for-action',
},
{
label: 'Multiple Languages',
- path: '/guides/best-practices/multiple-languages',
+ path: '/guides/multiple-languages',
},
{
label: 'Benchmark Performance',
- path: '/guides/best-practices/benchmark-performance',
+ path: '/guides/benchmark-performance',
},
// Add more links here as needed
];