Compare commits

..

292 Commits

Author SHA1 Message Date
Alex Janousek
bbe1e44366 Merge pull request #2457 from GSA/dependabot/npm_and_yarn/tar-fs-3.0.8
Bump tar-fs from 3.0.6 to 3.0.8
2025-03-29 08:48:34 -04:00
Alex Janousek
685deebae4 Merge pull request #2459 from GSA/dependabot/pip/click-8.1.8
Bump click from 8.1.7 to 8.1.8
2025-03-29 08:48:17 -04:00
dependabot[bot]
918016d4af Bump click from 8.1.7 to 8.1.8
Bumps [click](https://github.com/pallets/click) from 8.1.7 to 8.1.8.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/click/compare/8.1.7...8.1.8)

---
updated-dependencies:
- dependency-name: click
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-29 12:24:29 +00:00
Alex Janousek
f87f0a1c9e Merge pull request #2454 from GSA/dependabot/pip/flake8-bugbear-24.12.12
Bump flake8-bugbear from 24.8.19 to 24.12.12
2025-03-29 08:22:37 -04:00
dependabot[bot]
869f76c846 Bump tar-fs from 3.0.6 to 3.0.8
Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 3.0.6 to 3.0.8.
- [Commits](https://github.com/mafintosh/tar-fs/compare/v3.0.6...v3.0.8)

---
updated-dependencies:
- dependency-name: tar-fs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 22:19:50 +00:00
dependabot[bot]
3946e7bb3a Bump flake8-bugbear from 24.8.19 to 24.12.12
Bumps [flake8-bugbear](https://github.com/PyCQA/flake8-bugbear) from 24.8.19 to 24.12.12.
- [Release notes](https://github.com/PyCQA/flake8-bugbear/releases)
- [Commits](https://github.com/PyCQA/flake8-bugbear/compare/24.8.19...24.12.12)

---
updated-dependencies:
- dependency-name: flake8-bugbear
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 19:06:58 +00:00
Alex Janousek
56ee7ec376 Merge pull request #2453 from GSA/dependabot/pip/pyexcel-io-0.6.7
Bump pyexcel-io from 0.6.6 to 0.6.7
2025-03-28 15:04:58 -04:00
dependabot[bot]
5dad9e8f0f Bump pyexcel-io from 0.6.6 to 0.6.7
Bumps [pyexcel-io](https://github.com/pyexcel/pyexcel-io) from 0.6.6 to 0.6.7.
- [Release notes](https://github.com/pyexcel/pyexcel-io/releases)
- [Changelog](https://github.com/pyexcel/pyexcel-io/blob/dev/CHANGELOG.rst)
- [Commits](https://github.com/pyexcel/pyexcel-io/compare/v0.6.6...v0.6.7)

---
updated-dependencies:
- dependency-name: pyexcel-io
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 18:03:48 +00:00
Alex Janousek
23c5d7aff1 Merge pull request #2455 from GSA/dependabot/pip/humanize-4.12.2
Bump humanize from 4.11.0 to 4.12.2
2025-03-28 14:01:57 -04:00
dependabot[bot]
d2dd249b61 Bump humanize from 4.11.0 to 4.12.2
Bumps [humanize](https://github.com/python-humanize/humanize) from 4.11.0 to 4.12.2.
- [Release notes](https://github.com/python-humanize/humanize/releases)
- [Commits](https://github.com/python-humanize/humanize/compare/4.11.0...4.12.2)

---
updated-dependencies:
- dependency-name: humanize
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 17:08:41 +00:00
Alex Janousek
3e410ba5b2 Merge pull request #2456 from GSA/dependabot/pip/python-dotenv-1.1.0
Bump python-dotenv from 1.0.1 to 1.1.0
2025-03-28 13:06:49 -04:00
ccostino
a1802a3439 Merge pull request #2451 from GSA/2450-missing-title-visibility
css update pill label to show visibility
2025-03-28 09:56:00 -04:00
dependabot[bot]
8897b30b81 Bump python-dotenv from 1.0.1 to 1.1.0
Bumps [python-dotenv](https://github.com/theskumar/python-dotenv) from 1.0.1 to 1.1.0.
- [Release notes](https://github.com/theskumar/python-dotenv/releases)
- [Changelog](https://github.com/theskumar/python-dotenv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/theskumar/python-dotenv/compare/v1.0.1...v1.1.0)

---
updated-dependencies:
- dependency-name: python-dotenv
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 00:00:36 +00:00
Beverly Nguyen
b0d8eda0f4 css update pill label 2025-03-27 14:41:45 -07:00
Beverly Nguyen
e007571ac8 Merge pull request #2427 from GSA/1134-change-brackets-to-parenthesis
1134 - Changing all instances of the word "brackets" to "parenthesis"
2025-03-27 13:34:49 -07:00
Alex Janousek
6e72bc7f5e Merge pull request #2446 from GSA/dependabot/pip/regex-2024.11.6
Bump regex from 2024.9.11 to 2024.11.6
2025-03-27 13:04:26 -04:00
dependabot[bot]
f4bc6d4531 Bump regex from 2024.9.11 to 2024.11.6
Bumps [regex](https://github.com/mrabarnett/mrab-regex) from 2024.9.11 to 2024.11.6.
- [Changelog](https://github.com/mrabarnett/mrab-regex/blob/hg/changelog.txt)
- [Commits](https://github.com/mrabarnett/mrab-regex/compare/2024.9.11...2024.11.6)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-27 16:48:27 +00:00
Alex Janousek
a5200220e2 Merge pull request #2445 from GSA/dependabot/pip/black-25.1.0
Bump black from 24.10.0 to 25.1.0
2025-03-27 12:46:28 -04:00
dependabot[bot]
8f45eeb2cf Bump black from 24.10.0 to 25.1.0
Bumps [black](https://github.com/psf/black) from 24.10.0 to 25.1.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/24.10.0...25.1.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-27 14:01:27 +00:00
Alex Janousek
b134a68845 Merge pull request #2444 from GSA/dependabot/pip/flake8-pytest-style-2.1.0
Bump flake8-pytest-style from 2.0.0 to 2.1.0
2025-03-27 09:59:44 -04:00
Alex Janousek
4b910bec88 Merge pull request #2443 from GSA/dependabot/pip/moto-5.1.1
Bump moto from 5.0.22 to 5.1.1
2025-03-27 09:59:32 -04:00
dependabot[bot]
238a281512 Bump flake8-pytest-style from 2.0.0 to 2.1.0
Bumps [flake8-pytest-style](https://github.com/m-burst/flake8-pytest-style) from 2.0.0 to 2.1.0.
- [Commits](https://github.com/m-burst/flake8-pytest-style/compare/v2.0.0...v2.1.0)

---
updated-dependencies:
- dependency-name: flake8-pytest-style
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-26 23:50:21 +00:00
dependabot[bot]
cafd7d75b7 Bump moto from 5.0.22 to 5.1.1
Bumps [moto](https://github.com/getmoto/moto) from 5.0.22 to 5.1.1.
- [Release notes](https://github.com/getmoto/moto/releases)
- [Changelog](https://github.com/getmoto/moto/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getmoto/moto/compare/5.0.22...5.1.1)

---
updated-dependencies:
- dependency-name: moto
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-26 23:50:01 +00:00
Alex Janousek
7458acdab1 Merge pull request #2437 from GSA/dependabot/pip/charset-normalizer-3.4.1
Bump charset-normalizer from 3.4.0 to 3.4.1
2025-03-26 11:00:43 -04:00
dependabot[bot]
c7e3d777ac Bump charset-normalizer from 3.4.0 to 3.4.1
Bumps [charset-normalizer](https://github.com/jawah/charset_normalizer) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/jawah/charset_normalizer/releases)
- [Changelog](https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jawah/charset_normalizer/compare/3.4.0...3.4.1)

---
updated-dependencies:
- dependency-name: charset-normalizer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-26 14:45:59 +00:00
Alex Janousek
ec45db1ea4 Merge pull request #2438 from GSA/dependabot/pip/boto3-1.35.99
Bump boto3 from 1.35.51 to 1.35.99
2025-03-26 10:44:10 -04:00
dependabot[bot]
9bed7d4253 Bump boto3 from 1.35.51 to 1.35.99
Bumps [boto3](https://github.com/boto/boto3) from 1.35.51 to 1.35.99.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.35.51...1.35.99)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-26 14:19:42 +00:00
Alex Janousek
8c56a75af7 Merge pull request #2439 from GSA/dependabot/pip/beautifulsoup4-4.13.3
Bump beautifulsoup4 from 4.12.3 to 4.13.3
2025-03-26 10:17:45 -04:00
dependabot[bot]
d9eebb4f64 Bump beautifulsoup4 from 4.12.3 to 4.13.3
Bumps [beautifulsoup4](https://www.crummy.com/software/BeautifulSoup/bs4/) from 4.12.3 to 4.13.3.

---
updated-dependencies:
- dependency-name: beautifulsoup4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-26 13:54:18 +00:00
Alex Janousek
6546acf434 Merge pull request #2433 from GSA/dependabot/pip/pyexcel-xls-0.7.1
Bump pyexcel-xls from 0.7.0 to 0.7.1
2025-03-26 09:52:21 -04:00
Jonathan Bobel
bd77775286 Merge pull request #2411 from GSA/2410-bug-radio-buttons-cannot-be-selected
revert change back to params.for in order for user to select radio op…
2025-03-25 15:04:01 -04:00
dependabot[bot]
132ced0042 Bump pyexcel-xls from 0.7.0 to 0.7.1
Bumps [pyexcel-xls](https://github.com/pyexcel/pyexcel-xls) from 0.7.0 to 0.7.1.
- [Release notes](https://github.com/pyexcel/pyexcel-xls/releases)
- [Changelog](https://github.com/pyexcel/pyexcel-xls/blob/dev/CHANGELOG.rst)
- [Commits](https://github.com/pyexcel/pyexcel-xls/compare/v0.7.0...v0.7.1)

---
updated-dependencies:
- dependency-name: pyexcel-xls
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 18:52:49 +00:00
Alex Janousek
7922004f9a Merge pull request #2434 from GSA/dependabot/pip/cachetools-5.5.2
Bump cachetools from 5.5.0 to 5.5.2
2025-03-25 14:50:50 -04:00
dependabot[bot]
3a38ea2db6 Bump cachetools from 5.5.0 to 5.5.2
Bumps [cachetools](https://github.com/tkem/cachetools) from 5.5.0 to 5.5.2.
- [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tkem/cachetools/compare/v5.5.0...v5.5.2)

---
updated-dependencies:
- dependency-name: cachetools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 16:03:48 +00:00
Alex Janousek
3af8f782ec Merge pull request #2435 from GSA/dependabot/pip/pyexcel-0.7.2
Bump pyexcel from 0.7.0 to 0.7.2
2025-03-25 12:01:54 -04:00
dependabot[bot]
cbb1288345 Bump pyexcel from 0.7.0 to 0.7.2
Bumps [pyexcel](https://github.com/pyexcel/pyexcel) from 0.7.0 to 0.7.2.
- [Release notes](https://github.com/pyexcel/pyexcel/releases)
- [Changelog](https://github.com/pyexcel/pyexcel/blob/dev/CHANGELOG.rst)
- [Commits](https://github.com/pyexcel/pyexcel/compare/v0.7.0...v0.7.2)

---
updated-dependencies:
- dependency-name: pyexcel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 13:51:05 +00:00
Alex Janousek
96c033cd6f Merge pull request #2432 from GSA/dependabot/pip/certifi-2025.1.31
Bump certifi from 2024.8.30 to 2025.1.31
2025-03-25 09:49:09 -04:00
Alex Janousek
5d43ec2bb6 Merge pull request #2431 from GSA/dependabot/npm_and_yarn/rollup-4.37.0
Bump rollup from 4.36.0 to 4.37.0
2025-03-25 09:48:58 -04:00
dependabot[bot]
fff5caee1f Bump certifi from 2024.8.30 to 2025.1.31
Bumps [certifi](https://github.com/certifi/python-certifi) from 2024.8.30 to 2025.1.31.
- [Commits](https://github.com/certifi/python-certifi/compare/2024.08.30...2025.01.31)

---
updated-dependencies:
- dependency-name: certifi
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 01:14:54 +00:00
dependabot[bot]
6cfb15106e Bump rollup from 4.36.0 to 4.37.0
Bumps [rollup](https://github.com/rollup/rollup) from 4.36.0 to 4.37.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.36.0...v4.37.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 00:56:17 +00:00
Beverly Nguyen
5507891d8f Merge branch 'main' into 2410-bug-radio-buttons-cannot-be-selected 2025-03-24 12:49:04 -07:00
Beverly Nguyen
1a5f255539 jest fix 2025-03-24 12:48:28 -07:00
Beverly Nguyen
7e2a2bad8e update validation code 2025-03-24 12:33:01 -07:00
Alex Janousek
5c7a8913b0 Merge pull request #2316 from GSA/dependabot/pip/pytest-playwright-0.7.0
Bump pytest-playwright from 0.5.2 to 0.7.0
2025-03-24 12:28:40 -04:00
alexjanousekGSA
52a11945a1 Merge branch 'main' into dependabot/pip/pytest-playwright-0.7.0 2025-03-24 12:18:44 -04:00
Alex Janousek
79ea3a3ac9 Merge pull request #2429 from GSA/dependabot/pip/coverage-7.7.1
Bump coverage from 7.6.4 to 7.7.1
2025-03-24 12:16:31 -04:00
dependabot[bot]
88ff982c0d Bump coverage from 7.6.4 to 7.7.1
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.6.4 to 7.7.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.4...7.7.1)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-24 13:28:07 +00:00
ccostino
77c97eeb0b Merge pull request #2423 from GSA/dependabot/pip/numpy-2.2.4
Bump numpy from 2.2.3 to 2.2.4
2025-03-24 09:22:00 -04:00
dependabot[bot]
5d4394bfda Bump numpy from 2.2.3 to 2.2.4
Bumps [numpy](https://github.com/numpy/numpy) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst)
- [Commits](https://github.com/numpy/numpy/compare/v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: numpy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-22 14:29:50 +00:00
Alex Janousek
7485162411 Merge pull request #2430 from GSA/dependabot/pip/gunicorn-23.0.0
Bump gunicorn from 22.0.0 to 23.0.0
2025-03-22 10:27:58 -04:00
dependabot[bot]
d16c0c5153 Bump gunicorn from 22.0.0 to 23.0.0
Bumps [gunicorn](https://github.com/benoitc/gunicorn) from 22.0.0 to 23.0.0.
- [Release notes](https://github.com/benoitc/gunicorn/releases)
- [Commits](https://github.com/benoitc/gunicorn/compare/22.0.0...23.0.0)

---
updated-dependencies:
- dependency-name: gunicorn
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-22 14:07:53 +00:00
Alex Janousek
5144b90f22 Merge branch 'main' into dependabot/pip/pytest-playwright-0.7.0 2025-03-22 10:06:47 -04:00
Alex Janousek
418a868e18 Merge pull request #2422 from GSA/dependabot/pip/redis-5.2.1
Bump redis from 5.2.0 to 5.2.1
2025-03-22 10:05:57 -04:00
Beverly Nguyen
3a38b8bf31 fixed validation for radio and text input fields 2025-03-21 18:53:49 -07:00
Beverly Nguyen
04f4f2e990 Merge pull request #2428 from GSA/remove-about-feature-flag 2025-03-20 16:14:16 -07:00
alexjanousekGSA
9efe503353 Fixed linting issue 2025-03-20 14:32:44 -04:00
Jonathan Bobel
012dc4fae6 Merge pull request #2425 from GSA/2255-CSV-content-update
2255 - Content update for CSV upload area
2025-03-20 14:29:19 -04:00
alexjanousekGSA
35f3203e9c Removed feature flag 2025-03-20 14:22:41 -04:00
ccostino
cb4cfeb610 Merge pull request #2409 from GSA/2400-styling-on-the-template-page-is-off
fix styling issue
2025-03-20 13:37:18 -04:00
Jonathan Bobel
15103c99b5 Merge pull request #2403 from GSA/2298-bug-able-to-keep-pressing-send-and-send-more-and-more-while-processing
Prevent duplicate form submissions
2025-03-20 13:06:51 -04:00
Jonathan Bobel
6dd8b3cfe0 Update validators.py 2025-03-20 10:45:33 -04:00
Jonathan Bobel
fe098eca22 1134 - Changing all instances of the word "brackets" to "parenthesis" 2025-03-20 10:29:29 -04:00
Jonathan Bobel
0ca31c1ed1 Update send.html
Removed role attribute
2025-03-20 10:21:03 -04:00
Beverly Nguyen
78ee70b0c1 Merge branch 'main' into 2410-bug-radio-buttons-cannot-be-selected 2025-03-19 14:04:56 -07:00
Beverly Nguyen
71b7c745db Merge branch 'main' into 2400-styling-on-the-template-page-is-off 2025-03-19 14:02:57 -07:00
Beverly Nguyen
da194d358c removing comments 2025-03-19 13:13:29 -07:00
dependabot[bot]
a539fcbef6 Bump redis from 5.2.0 to 5.2.1
Bumps [redis](https://github.com/redis/redis-py) from 5.2.0 to 5.2.1.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v5.2.0...v5.2.1)

---
updated-dependencies:
- dependency-name: redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-19 20:07:25 +00:00
Beverly Nguyen
a5ddf8038b Merge pull request #2412 from GSA/2042-no-emojis-special-characters-plain-language
2042 no emojis special characters plain language
2025-03-19 13:05:32 -07:00
Jonathan Bobel
06d0581bc9 Update send.html 2025-03-19 15:54:55 -04:00
Jonathan Bobel
937aa5af15 Update templates.py 2025-03-19 14:35:22 -04:00
Jonathan Bobel
b5203f473a Adding the personalization message back in 2025-03-19 11:30:01 -04:00
ccostino
dc03a3f0d1 Merge pull request #2418 from GSA/feat/text-by-user-update
Updated FE to allow stats by user
2025-03-19 11:13:14 -04:00
Jonathan Bobel
7afdf7336a Update test_templates.py 2025-03-19 10:26:49 -04:00
Jonathan Bobel
bab13de934 Update test_validators.py
Fixing a test
2025-03-18 16:42:15 -04:00
Jonathan Bobel
c05beb42f2 Update templates.py 2025-03-18 16:28:30 -04:00
Jonathan Bobel
2049fd5c76 Fixing formatting errors 2025-03-18 16:07:58 -04:00
Jonathan Bobel
1d911c4d44 Updates to text area validation on template edit page 2025-03-18 15:55:01 -04:00
Jonathan Bobel
bc83fab764 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2042-no-emojis-special-characters-plain-language 2025-03-18 15:52:40 -04:00
Andrew Shumway
051114157d Merge pull request #2395 from GSA/dependabot/pip/newrelic-10.7.0
Bump newrelic from 10.6.0 to 10.7.0
2025-03-18 12:40:45 -06:00
Andrew Shumway
cac7d1452a Merge pull request #2396 from GSA/dependabot/pip/cryptography-44.0.2
Bump cryptography from 44.0.1 to 44.0.2
2025-03-18 12:35:37 -06:00
ecayer
f9ea913b00 Merge pull request #2419 from GSA/update_cert
add comment to force redeploy
2025-03-18 10:28:33 -07:00
Kenneth Kehl
9a8a80ab14 add comment 2025-03-18 10:19:02 -07:00
dependabot[bot]
707768d749 Bump newrelic from 10.6.0 to 10.7.0
Bumps [newrelic](https://github.com/newrelic/newrelic-python-agent) from 10.6.0 to 10.7.0.
- [Release notes](https://github.com/newrelic/newrelic-python-agent/releases)
- [Commits](https://github.com/newrelic/newrelic-python-agent/compare/v10.6.0...v10.7.0)

---
updated-dependencies:
- dependency-name: newrelic
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 16:54:44 +00:00
dependabot[bot]
d05bf1e9e0 Bump cryptography from 44.0.1 to 44.0.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.1 to 44.0.2.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/44.0.1...44.0.2)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 16:54:41 +00:00
Andrew Shumway
da081679c1 Merge pull request #2394 from GSA/dependabot/pip/flake8-7.1.2
Bump flake8 from 7.1.1 to 7.1.2
2025-03-18 10:52:49 -06:00
alexjanousekGSA
61c37687a2 Merge branch 'main' into feat/text-by-user-update 2025-03-18 11:21:25 -04:00
Alex Janousek
8bc6df5d35 Merge pull request #2392 from GSA/dependabot/npm_and_yarn/babel/core-7.26.10
Bump @babel/core from 7.26.9 to 7.26.10
2025-03-18 11:14:50 -04:00
Alex Janousek
e84e3efed3 Merge pull request #2393 from GSA/dependabot/npm_and_yarn/rollup/plugin-node-resolve-16.0.1
Bump @rollup/plugin-node-resolve from 16.0.0 to 16.0.1
2025-03-18 11:14:35 -04:00
Alex Janousek
fdceb3cbdb Merge pull request #2414 from GSA/dependabot/npm_and_yarn/rollup-4.36.0
Bump rollup from 4.35.0 to 4.36.0
2025-03-18 11:14:05 -04:00
Alex Janousek
26c695c21e Merge pull request #2415 from GSA/dependabot/npm_and_yarn/playwright-1.51.1
Bump playwright from 1.51.0 to 1.51.1
2025-03-18 11:13:52 -04:00
Alex Janousek
b4907fd2fb Merge pull request #2416 from GSA/dependabot/npm_and_yarn/sass-embedded-1.86.0
Bump sass-embedded from 1.85.1 to 1.86.0
2025-03-18 11:13:40 -04:00
alexjanousekGSA
f13ab20e93 Updated FE to allow stats by user 2025-03-18 11:09:09 -04:00
dependabot[bot]
9404a09dfa Bump sass-embedded from 1.85.1 to 1.86.0
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.85.1 to 1.86.0.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.85.1...1.86.0)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 00:08:10 +00:00
dependabot[bot]
fda16b7ce9 Bump playwright from 1.51.0 to 1.51.1
Bumps [playwright](https://github.com/microsoft/playwright) from 1.51.0 to 1.51.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.51.0...v1.51.1)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 00:06:13 +00:00
dependabot[bot]
3ae05a37c9 Bump rollup from 4.35.0 to 4.36.0
Bumps [rollup](https://github.com/rollup/rollup) from 4.35.0 to 4.36.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.35.0...v4.36.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 00:05:26 +00:00
ccostino
0df8b37646 Merge pull request #2413 from GSA/ugh_fix
ugh
2025-03-17 19:38:05 -04:00
Kenneth Kehl
cb334c0dcd ugh 2025-03-17 16:28:46 -07:00
Beverly Nguyen
1cd51a8257 remove comment 2025-03-17 16:04:09 -07:00
Beverly Nguyen
3b8fdd8122 remove comment 2025-03-17 15:46:25 -07:00
Jonathan Bobel
43c0d6244a Addressing a test 2025-03-17 16:49:30 -04:00
Jonathan Bobel
fbf0fb1f0d 2042 - Updates to the error message regarding special characters 2025-03-17 16:47:45 -04:00
Beverly Nguyen
965db9cd7e revert change back to params.for in order for user to select radio option 2025-03-17 13:45:19 -07:00
Beverly Nguyen
3555db1163 fix styling issue 2025-03-17 12:12:06 -07:00
ccostino
f820ae86f3 Merge pull request #2408 from GSA/ugh_fix
initial
2025-03-17 15:07:52 -04:00
Kenneth Kehl
47657d45ed initial 2025-03-17 09:57:15 -07:00
Beverly Nguyen
fab1ef6d45 jest 2025-03-14 13:56:48 -07:00
Beverly Nguyen
10fb9f9b35 jest 2025-03-14 13:54:20 -07:00
Beverly Nguyen
02a188a080 fixed e2e 2025-03-14 13:47:02 -07:00
Beverly Nguyen
9facde2c60 Merge pull request #2397 from GSA/2391-youtube-video-not-playing
2391 - Updating Cross Origin code to allow Youtube
2025-03-14 12:53:59 -07:00
ccostino
592ea83ea2 Merge pull request #2406 from GSA/content-updates
update banner color
2025-03-14 14:21:53 -04:00
Beverly Nguyen
dd0d5d3b33 update banner color 2025-03-14 11:11:42 -07:00
Beverly Nguyen
29373d41ca Merge branch 'main' into 2298-bug-able-to-keep-pressing-send-and-send-more-and-more-while-processing 2025-03-14 11:05:32 -07:00
Beverly Nguyen
55225018b6 remove comments 2025-03-14 09:28:59 -07:00
Jonathan Bobel
5a1b656d7e Update notifications_utils/request_helper.py
Co-authored-by: ccostino <ccostino@users.noreply.github.com>
2025-03-14 12:13:52 -04:00
ccostino
46e43b6fbd Merge pull request #2399 from GSA/2398-broken-tts-link
2398 - broken TTS link
2025-03-14 11:40:51 -04:00
ccostino
542ce8ec00 Merge pull request #2404 from GSA/content-updates
content updates
2025-03-14 10:56:44 -04:00
Beverly Nguyen
371fbb2cd4 fixed test and e2e 2025-03-13 21:49:40 -07:00
Beverly Nguyen
41dcedd48f update to nav 2025-03-13 15:54:14 -07:00
Beverly Nguyen
d64d84ff4a flake8 2025-03-13 15:51:24 -07:00
Beverly Nguyen
558753037f content updates 2025-03-13 15:43:21 -07:00
Beverly Nguyen
821265cf6e preventing users from double click on submit 2025-03-13 15:04:12 -07:00
Jonathan Bobel
236fafd597 Update request_helper.py 2025-03-13 14:26:45 -04:00
Jonathan Bobel
22d643acb1 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2391-youtube-video-not-playing 2025-03-13 14:24:13 -04:00
ccostino
ff65471084 Merge pull request #2371 from GSA/2355-updateremove-unnecessary-componentsmacros-that-is-using-ajax-to-call-to-servers
remove dead code from dashboard
2025-03-12 16:25:16 -04:00
Beverly Nguyen
310ec3eae6 merge main 2025-03-12 13:17:03 -07:00
Jonathan Bobel
9e8aec4c5d 2398 - broken TTS link
Updating TTS link, maybe the link used to go to a page that was removed
2025-03-12 15:37:51 -04:00
Beverly Nguyen
de67e441f9 removing comments 2025-03-12 12:11:46 -07:00
Beverly Nguyen
e3b35b5b83 quick update to imports and variables used 2025-03-12 10:08:48 -07:00
Jonathan Bobel
21408543d4 Update request_helper.py
Adjusting cross-origin checks to allow Youtube
2025-03-12 12:52:32 -04:00
dependabot[bot]
aff028b24c Bump flake8 from 7.1.1 to 7.1.2
Bumps [flake8](https://github.com/pycqa/flake8) from 7.1.1 to 7.1.2.
- [Commits](https://github.com/pycqa/flake8/compare/7.1.1...7.1.2)

---
updated-dependencies:
- dependency-name: flake8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-12 00:02:15 +00:00
dependabot[bot]
a652c5f321 Bump @rollup/plugin-node-resolve from 16.0.0 to 16.0.1
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 16.0.0 to 16.0.1.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/node-resolve-v16.0.1/packages/node-resolve)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-node-resolve"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-11 23:18:00 +00:00
dependabot[bot]
06814cd0a5 Bump @babel/core from 7.26.9 to 7.26.10
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.9 to 7.26.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-11 23:17:51 +00:00
Beverly Nguyen
dd7d32e51c remove extra code 2025-03-11 12:45:29 -07:00
Jonathan Bobel
a5d66f02b5 Merge pull request #2356 from GSA/2214-client-side-validation
2214 client side validation
2025-03-11 14:45:51 -04:00
Jonathan Bobel
505e5792d2 Merge pull request #2273 from GSA/2200-contextual-tooltips
2200 - Adding tooltip to Total messages header for explanation
2025-03-11 14:42:43 -04:00
Jonathan Bobel
f73fe7fc9a Update _data-visualization.scss
Removing commented code
2025-03-11 14:09:22 -04:00
Jonathan Bobel
aa3d5757f1 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2200-contextual-tooltips 2025-03-11 12:52:17 -04:00
Beverly Nguyen
85ae22a81a Merge pull request #2390 from GSA/2043-soften-our-word-choice-charge-since-we-are-not-making-people-pay-yet
Updated copy to be more verbose
2025-03-11 09:49:07 -07:00
Jonathan Bobel
ae619fff64 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2200-contextual-tooltips 2025-03-11 12:48:49 -04:00
ccostino
9f88a3d84f Merge pull request #2349 from GSA/dependabot/pip/pre-commit-4.1.0
Bump pre-commit from 3.8.0 to 4.1.0
2025-03-11 11:52:57 -04:00
alexjanousekGSA
f828193a5c Updated copy to be more verbose 2025-03-11 11:46:46 -04:00
dependabot[bot]
bc9d8969fb Bump pre-commit from 3.8.0 to 4.1.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.8.0 to 4.1.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.8.0...v4.1.0)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-11 14:35:46 +00:00
ccostino
7ab59b9d4a Merge pull request #2333 from GSA/dependabot/pip/numpy-2.2.3
Bump numpy from 1.26.4 to 2.2.3
2025-03-11 10:33:55 -04:00
dependabot[bot]
b7673ae673 Bump numpy from 1.26.4 to 2.2.3
Bumps [numpy](https://github.com/numpy/numpy) from 1.26.4 to 2.2.3.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst)
- [Commits](https://github.com/numpy/numpy/compare/v1.26.4...v2.2.3)

---
updated-dependencies:
- dependency-name: numpy
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-11 14:16:14 +00:00
Kenneth Kehl
cee9b751bf Merge pull request #2389 from GSA/dependabot/npm_and_yarn/rollup-4.35.0
Bump rollup from 4.34.9 to 4.35.0
2025-03-11 07:14:38 -07:00
Kenneth Kehl
7b39aa4761 Merge pull request #2387 from GSA/dependabot/pip/python-json-logger-3.3.0
Bump python-json-logger from 2.0.7 to 3.3.0
2025-03-11 07:14:12 -07:00
dependabot[bot]
6a224528a5 Bump rollup from 4.34.9 to 4.35.0
Bumps [rollup](https://github.com/rollup/rollup) from 4.34.9 to 4.35.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.34.9...v4.35.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-11 00:28:56 +00:00
Beverly Nguyen
56440b4477 Merge branch 'main' into 2355-updateremove-unnecessary-componentsmacros-that-is-using-ajax-to-call-to-servers 2025-03-10 16:54:30 -07:00
Beverly Nguyen
0a75856c2d fix unit testing 2025-03-10 16:54:02 -07:00
dependabot[bot]
59da570302 Bump python-json-logger from 2.0.7 to 3.3.0
Bumps [python-json-logger](https://github.com/nhairs/python-json-logger) from 2.0.7 to 3.3.0.
- [Release notes](https://github.com/nhairs/python-json-logger/releases)
- [Changelog](https://github.com/nhairs/python-json-logger/blob/main/docs/changelog.md)
- [Commits](https://github.com/nhairs/python-json-logger/compare/v2.0.7...v3.3.0)

---
updated-dependencies:
- dependency-name: python-json-logger
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 18:14:16 +00:00
ccostino
714473b829 Merge pull request #2388 from GSA/cant_change_phone_number
fix code alignment issue resulting in missing endpoint
2025-03-10 14:12:10 -04:00
Kenneth Kehl
ee04cae75c merge from main 2025-03-10 09:59:20 -07:00
Alex Janousek
113f86b312 Merge pull request #2386 from GSA/dependabot/npm_and_yarn/uswds/uswds-3.12.0
Bump @uswds/uswds from 3.11.0 to 3.12.0
2025-03-10 12:17:59 -04:00
Kenneth Kehl
224c25a193 fix code alignment issue resulting in missing endpoint 2025-03-10 08:22:49 -07:00
dependabot[bot]
adf37eb4d0 Bump pytest-playwright from 0.5.2 to 0.7.0
Bumps [pytest-playwright](https://github.com/microsoft/playwright-pytest) from 0.5.2 to 0.7.0.
- [Release notes](https://github.com/microsoft/playwright-pytest/releases)
- [Commits](https://github.com/microsoft/playwright-pytest/compare/v0.5.2...v0.7.0)

---
updated-dependencies:
- dependency-name: pytest-playwright
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-10 14:32:40 +00:00
dependabot[bot]
e6ded78be8 Bump @uswds/uswds from 3.11.0 to 3.12.0
Bumps [@uswds/uswds](https://github.com/uswds/uswds) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/uswds/uswds/releases)
- [Commits](https://github.com/uswds/uswds/compare/v3.11.0...v3.12.0)

---
updated-dependencies:
- dependency-name: "@uswds/uswds"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-07 23:42:00 +00:00
ccostino
f6952b28de Merge pull request #2381 from GSA/2307-update-message-part-content-on-trial-mode-page
Copy updates
2025-03-07 09:09:52 -05:00
Alex Janousek
3408cf0bd8 Merge pull request #2383 from GSA/dependabot/npm_and_yarn/playwright-1.51.0
Bump playwright from 1.50.1 to 1.51.0
2025-03-07 08:48:26 -05:00
Alex Janousek
8f0daa19b8 Merge pull request #2384 from GSA/dependabot/npm_and_yarn/rollup/plugin-commonjs-28.0.3
Bump @rollup/plugin-commonjs from 28.0.2 to 28.0.3
2025-03-07 08:48:10 -05:00
dependabot[bot]
59f766bb1e Bump @rollup/plugin-commonjs from 28.0.2 to 28.0.3
Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 28.0.2 to 28.0.3.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/commonjs/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v28.0.3/packages/commonjs)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-commonjs"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-06 23:56:27 +00:00
dependabot[bot]
ec2b55c171 Bump playwright from 1.50.1 to 1.51.0
Bumps [playwright](https://github.com/microsoft/playwright) from 1.50.1 to 1.51.0.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.50.1...v1.51.0)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-06 23:56:15 +00:00
alexjanousekGSA
3fbbc4d57e Removed a word 2025-03-06 15:58:58 -05:00
Jonathan Bobel
32c797e10b Update send.py 2025-03-06 15:56:47 -05:00
alexjanousekGSA
01a940681e Merge branch 'main' into 2307-update-message-part-content-on-trial-mode-page 2025-03-06 15:37:23 -05:00
Jonathan Bobel
bd96cc1d20 Update activityChart.test.js
Hmm this failed locally but not when committed. Reverting.
2025-03-06 15:19:27 -05:00
Jonathan Bobel
71f7ed051c Merge branch 'main' of https://github.com/GSA/notifications-admin into 2214-client-side-validation 2025-03-06 15:14:21 -05:00
Kenneth Kehl
221f1f30fd Merge pull request #2379 from GSA/dependabot/pip/jinja2-3.1.6
Bump jinja2 from 3.1.5 to 3.1.6
2025-03-06 12:13:43 -08:00
Jonathan Bobel
1696614995 Update activityChart.test.js 2025-03-06 15:00:21 -05:00
ccostino
8415665bb1 Merge pull request #2369 from GSA/2305-remove-message-parts-reference-on-contact-us-page
Removed text from logged in contact us page
2025-03-06 12:52:01 -05:00
alexjanousekGSA
0254dc41ca Copy updates 2025-03-06 12:43:23 -05:00
Jonathan Bobel
a18f981b1c Merge branch 'main' of https://github.com/GSA/notifications-admin into 2214-client-side-validation 2025-03-06 12:12:50 -05:00
dependabot[bot]
cb2a7b5716 Bump jinja2 from 3.1.5 to 3.1.6
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.5 to 3.1.6.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.5...3.1.6)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-06 04:48:03 +00:00
Beverly Nguyen
1f14c1e570 isort 2025-03-05 14:00:05 -08:00
Deana VanCura
7d4e2cce25 Delete unusable media 4 2025-03-05 15:18:09 -05:00
Deana VanCura
e48a90a40c Delete unusable media 3 2025-03-05 15:17:42 -05:00
Deana VanCura
38ef9742c8 Delete unusable media 2 2025-03-05 15:17:24 -05:00
Deana VanCura
7dfb4294e1 Delete unusable media 1 2025-03-05 15:16:28 -05:00
ccostino
5be95b85c1 Merge pull request #2372 from GSA/new-pdf
new static files
2025-03-05 14:35:27 -05:00
Beverly Nguyen
2bec392a59 asap pdf 2025-03-05 10:53:08 -08:00
Beverly Nguyen
dd9cbe2f4b pdf 2025-03-05 10:48:40 -08:00
Deana VanCura
6fff2fb122 Add files via upload 2025-03-05 13:20:51 -05:00
Beverly Nguyen
3f7a84b17c flake8 2025-03-04 21:28:21 -08:00
Beverly Nguyen
e59516562f remove dead code from dashboard 2025-03-04 21:14:53 -08:00
alexjanousekGSA
9e01f3cd24 Removed text 2025-03-04 15:36:50 -05:00
Jonathan Bobel
241cf8c021 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2214-client-side-validation 2025-03-04 15:07:24 -05:00
ccostino
2ef7f2e252 Merge pull request #2367 from GSA/BUG-ubuntu-version-a11y-scan
Update checks.yml
2025-03-04 14:22:33 -05:00
Jonathan Bobel
7144eaa00d Update .pa11yci 2025-03-04 14:04:35 -05:00
Jonathan Bobel
ceb13a9051 Update .pa11yci
Trying a fix for the ubuntu situation
2025-03-04 13:35:37 -05:00
Alex Janousek
e958e097aa Merge pull request #2366 from GSA/dependabot/npm_and_yarn/rollup-4.34.9
Bump rollup from 4.34.8 to 4.34.9
2025-03-04 12:09:28 -05:00
Jonathan Bobel
20012885b1 Update checks.yml 2025-03-04 11:26:21 -05:00
Jonathan Bobel
b1b4611c55 Update checks.yml
Seeing if this fixes the a11y scan
2025-03-04 11:24:50 -05:00
dependabot[bot]
9ae1f40376 Bump rollup from 4.34.8 to 4.34.9
Bumps [rollup](https://github.com/rollup/rollup) from 4.34.8 to 4.34.9.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.34.8...v4.34.9)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-04 00:04:45 +00:00
Jonathan Bobel
3dee60fcc0 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2214-client-side-validation 2025-03-03 16:11:05 -05:00
Jonathan Bobel
94f881477e Focusing validation on individual form with one input 2025-03-03 13:33:45 -05:00
Jonathan Bobel
f4ca597964 Updates to validation.js and it's test - all are passing 2025-02-28 11:31:47 -05:00
Jonathan Bobel
a5146fc58a Fixing tests 2025-02-27 14:21:43 -05:00
Beverly Nguyen
0df04cfd89 Merge pull request #2325 from GSA/jb-add-accessibility-documentation
Create manual-a11y-checklist.md
2025-02-27 10:04:49 -08:00
Beverly Nguyen
34f7c6a4da Merge pull request #2361 from GSA/dependabot/npm_and_yarn/sass-embedded-1.85.1
Bump sass-embedded from 1.85.0 to 1.85.1
2025-02-27 10:04:10 -08:00
ccostino
cd78710753 Merge pull request #2359 from GSA/1543-review-and-update-total-messages-chart-on-dashboard-and-usagehtml-with-new-data-from-backend
Total message ratio update
2025-02-27 11:00:49 -05:00
Alex Janousek
102d005e0d Merge pull request #2362 from GSA/feat/fe-tz-change
Added local/utc time conversion for text metrics
2025-02-26 14:59:44 -05:00
Beverly Nguyen
3455235a8b fix test 2025-02-26 10:19:47 -08:00
Jonathan Bobel
f031f4bf18 Update template.njk
Experimenting with setting the "for"
2025-02-26 12:53:06 -05:00
Beverly Nguyen
c93d00dcbe fix test 2025-02-26 09:50:49 -08:00
Jonathan Bobel
ffda07b6bd Update test_tour.py 2025-02-26 12:24:18 -05:00
Jonathan Bobel
e769d421be Update test_tour.py 2025-02-26 12:19:15 -05:00
Jonathan Bobel
0daf140b39 Update test_manage_users.py 2025-02-26 12:09:34 -05:00
Jonathan Bobel
4225559677 Update test_manage_users.py 2025-02-26 11:57:26 -05:00
Jonathan Bobel
69457c873d Update test_manage_users.py 2025-02-26 11:41:30 -05:00
Jonathan Bobel
06c099b567 Update test_manage_users.py 2025-02-26 11:20:04 -05:00
alexjanousekGSA
a524ed0dc5 Fixed a test 2025-02-26 11:16:52 -05:00
alexjanousekGSA
c37bb44e0a Added unit tests for new utc conversion logic 2025-02-26 11:11:47 -05:00
dependabot[bot]
0b3177e3ff Bump sass-embedded from 1.85.0 to 1.85.1
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.85.0 to 1.85.1.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.85.0...1.85.1)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-25 23:49:03 +00:00
Beverly Nguyen
baf9b69fbb fix pytest 2025-02-25 14:01:56 -08:00
Beverly Nguyen
df3e2264ec flake8 2025-02-25 13:19:59 -08:00
Beverly Nguyen
79192e29b6 fix jest testing 2025-02-25 13:12:55 -08:00
Jonathan Bobel
ed79352201 Update test_manage_users.py
Removed print
2025-02-25 14:18:51 -05:00
Jonathan Bobel
df4979277a Adjusting tests 2025-02-25 13:58:49 -05:00
Jonathan Bobel
becdfc79d2 Update test_service_settings.py
Removing a print
2025-02-25 12:47:54 -05:00
Jonathan Bobel
951cb0fef9 Update test_activity.py 2025-02-25 12:28:39 -05:00
Jonathan Bobel
2b07517e9c Fixing tests 2025-02-25 12:23:56 -05:00
Jonathan Bobel
bb0d9a25b7 Update __init__.py
Fixing import
2025-02-25 11:36:53 -05:00
Jonathan Bobel
dc1bff6d19 Update __init__.py
Moved the import statement
2025-02-25 11:14:15 -05:00
Beverly Nguyen
5cede78661 Merge branch 'main' into 1543-review-and-update-total-messages-chart-on-dashboard-and-usagehtml-with-new-data-from-backend 2025-02-24 14:49:28 -08:00
Beverly Nguyen
5c9d190021 total message ratio update 2025-02-24 14:44:43 -08:00
Beverly Nguyen
61fb59f1cb total message ratio update 2025-02-24 14:08:26 -08:00
Jonathan Bobel
2bb318493a Fixing tests, adding dynamic slug 2025-02-24 16:11:42 -05:00
Jonathan Bobel
b6f341ee04 Update test_organizations.py
Fixing tests
2025-02-24 15:34:52 -05:00
Jonathan Bobel
91c2ae6733 Update template.njk
Reverting this change
2025-02-24 15:27:51 -05:00
Jonathan Bobel
0fa8c571c8 Update test_organizations.py
Fixing a test
2025-02-24 14:50:29 -05:00
Jonathan Bobel
70dae9c208 Update test_organizations.py
Adjusting a test
2025-02-24 14:18:00 -05:00
Jonathan Bobel
46524aa5f8 Merge branch 'main' of https://github.com/GSA/notifications-admin into 2214-client-side-validation 2025-02-24 12:30:19 -05:00
Jonathan Bobel
adab5f1338 2214 Client-side validation 2025-02-24 12:29:58 -05:00
Kenneth Kehl
02f39bd077 Merge pull request #2354 from GSA/fix_runaway_report_generation
fix runaway report generation
2025-02-21 10:13:37 -08:00
Kenneth Kehl
1eb12b93f1 fix runaway report generation 2025-02-21 09:22:29 -08:00
ccostino
f9fd580c58 Merge pull request #2350 from GSA/fix-terraform-actions
Update Terraform installation and configuration
2025-02-20 10:52:30 -05:00
Carlo Costino
fe6921e243 Update Terraform installation and configuration
This changeset accounts for having to explicitly install Terraform and updates our user configuration in several environments to account for team member changes.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2025-02-19 21:41:32 -05:00
Beverly Nguyen
d20f887f0b Merge pull request #2346 from GSA/update-github-actions 2025-02-19 14:24:01 -08:00
Carlo Costino
eadd8dddb5 Update GitHub Action References
This changeset updates many of our GitHub Action references to point to the latest versions to ensure they are kept up-to-date.  This helps address any improvements and security patches that have been made to them.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2025-02-19 16:56:09 -05:00
ccostino
77248b8bf0 Merge pull request #2345 from GSA/2344-reverting-back-100000-messages-to-250000-messages-in-front-of-login
reverting back to 250,000
2025-02-19 14:23:59 -05:00
Andrew Shumway
a8d036a3e5 Merge pull request #2340 from GSA/dependabot/pip/pyproj-3.7.1
Bump pyproj from 3.6.1 to 3.7.1
2025-02-19 12:22:49 -07:00
dependabot[bot]
05a746a042 Bump pyproj from 3.6.1 to 3.7.1
Bumps [pyproj](https://github.com/pyproj4/pyproj) from 3.6.1 to 3.7.1.
- [Release notes](https://github.com/pyproj4/pyproj/releases)
- [Changelog](https://github.com/pyproj4/pyproj/blob/main/docs/history.rst)
- [Commits](https://github.com/pyproj4/pyproj/compare/3.6.1...3.7.1)

---
updated-dependencies:
- dependency-name: pyproj
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-19 18:58:30 +00:00
Andrew Shumway
84acce48c4 Merge pull request #2335 from GSA/dependabot/pip/newrelic-10.6.0
Bump newrelic from 10.2.0 to 10.6.0
2025-02-19 11:55:21 -07:00
Beverly Nguyen
1bbc49c0ad reverting back to 250,000 2025-02-19 10:06:41 -08:00
Alex Janousek
bcd7ead5ec Merge pull request #2338 from GSA/dependabot/npm_and_yarn/babel/core-7.26.9
Bump @babel/core from 7.26.8 to 7.26.9
2025-02-19 12:52:53 -05:00
ccostino
0405c92f69 Merge pull request #2311 from GSA/2171-clean-up-titles
Pluralization around text, fixing conditionals, making bar chart more visible
2025-02-19 12:45:20 -05:00
Beverly Nguyen
ad1f83e80e Merge branch 'main' into 2171-clean-up-titles 2025-02-19 09:05:16 -08:00
dependabot[bot]
44778349f0 Bump @babel/core from 7.26.8 to 7.26.9
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.8 to 7.26.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.9/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-19 16:28:48 +00:00
Alex Janousek
5b46a4e1d7 Merge pull request #2337 from GSA/dependabot/npm_and_yarn/babel/preset-env-7.26.9
Bump @babel/preset-env from 7.26.7 to 7.26.9
2025-02-19 11:27:43 -05:00
Alex Janousek
91bea21607 Merge pull request #2339 from GSA/dependabot/npm_and_yarn/sass-embedded-1.85.0
Bump sass-embedded from 1.83.4 to 1.85.0
2025-02-19 11:27:33 -05:00
Alex Janousek
ab497be1f8 Merge pull request #2341 from GSA/dependabot/npm_and_yarn/rollup-4.34.8
Bump rollup from 4.34.6 to 4.34.8
2025-02-19 11:27:15 -05:00
dependabot[bot]
5b88eefe27 Bump rollup from 4.34.6 to 4.34.8
Bumps [rollup](https://github.com/rollup/rollup) from 4.34.6 to 4.34.8.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.34.6...v4.34.8)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 23:50:56 +00:00
dependabot[bot]
34e8647fba Bump sass-embedded from 1.83.4 to 1.85.0
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.83.4 to 1.85.0.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.83.4...1.85.0)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-14 23:48:09 +00:00
dependabot[bot]
2fdedc1b4f Bump @babel/preset-env from 7.26.7 to 7.26.9
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.26.7 to 7.26.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.9/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-14 23:47:50 +00:00
dependabot[bot]
db1f929dba Bump newrelic from 10.2.0 to 10.6.0
Bumps [newrelic](https://github.com/newrelic/newrelic-python-agent) from 10.2.0 to 10.6.0.
- [Release notes](https://github.com/newrelic/newrelic-python-agent/releases)
- [Commits](https://github.com/newrelic/newrelic-python-agent/compare/v10.2.0...v10.6.0)

---
updated-dependencies:
- dependency-name: newrelic
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-13 23:35:51 +00:00
Andrew Shumway
e7953262a3 Merge pull request #2329 from GSA/dependabot/pip/botocore-1.35.99
Bump botocore from 1.35.51 to 1.35.99
2025-02-13 10:44:03 -07:00
dependabot[bot]
89cfbd989d Bump botocore from 1.35.51 to 1.35.99
Bumps [botocore](https://github.com/boto/botocore) from 1.35.51 to 1.35.99.
- [Commits](https://github.com/boto/botocore/compare/1.35.51...1.35.99)

---
updated-dependencies:
- dependency-name: botocore
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-12 21:41:11 +00:00
Andrew Shumway
479cca3adb Merge pull request #2330 from GSA/dependabot/pip/cryptography-44.0.1
Bump cryptography from 43.0.3 to 44.0.1
2025-02-12 14:39:05 -07:00
dependabot[bot]
cc6a66f790 Bump cryptography from 43.0.3 to 44.0.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 43.0.3 to 44.0.1.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/43.0.3...44.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-11 19:17:18 +00:00
Alex Janousek
0c1dd129e0 Merge pull request #2326 from GSA/dependabot/npm_and_yarn/rollup-4.34.6
Bump rollup from 4.34.4 to 4.34.6
2025-02-11 11:41:40 -05:00
Alex Janousek
d70a80f4a6 Merge pull request #2328 from GSA/dependabot/npm_and_yarn/babel/core-7.26.8
Bump @babel/core from 7.26.7 to 7.26.8
2025-02-11 11:41:25 -05:00
dependabot[bot]
78cfafae94 Bump @babel/core from 7.26.7 to 7.26.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.26.7 to 7.26.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 23:18:16 +00:00
ccostino
3016aff185 Merge pull request #2261 from GSA/dependabot/pip/vulture-2.14
Bump vulture from 2.13 to 2.14
2025-02-10 16:13:02 -05:00
dependabot[bot]
4726143fb7 Bump vulture from 2.13 to 2.14
Bumps [vulture](https://github.com/jendrikseipp/vulture) from 2.13 to 2.14.
- [Release notes](https://github.com/jendrikseipp/vulture/releases)
- [Changelog](https://github.com/jendrikseipp/vulture/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jendrikseipp/vulture/compare/v2.13...v2.14)

---
updated-dependencies:
- dependency-name: vulture
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 19:06:21 +00:00
ccostino
a4963b8263 Merge pull request #2321 from GSA/notify-admin-2315
dynamic scan warnings
2025-02-10 14:05:22 -05:00
ccostino
22f729d652 Merge pull request #2289 from GSA/notify-admin-2286
redis report
2025-02-10 12:45:44 -05:00
dependabot[bot]
38fad44a15 Bump rollup from 4.34.4 to 4.34.6
Bumps [rollup](https://github.com/rollup/rollup) from 4.34.4 to 4.34.6.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.34.4...v4.34.6)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-07 23:58:26 +00:00
Jonathan Bobel
c1fa099c12 Create manual-a11y-checklist.md
Adding .md file for a11y documentation
2025-02-07 16:25:11 -05:00
Kenneth Kehl
208891a71a ignore source code disclosure java as a false positive 2025-02-06 11:42:31 -08:00
Kenneth Kehl
afd3d94790 try again 2025-02-06 11:33:58 -08:00
Kenneth Kehl
515419e0a2 try to block serving node files 2025-02-06 11:26:44 -08:00
Kenneth Kehl
d16eb70765 try to fix svg content type 2025-02-06 10:52:53 -08:00
Kenneth Kehl
39fd87064b try to remove comments 2025-02-06 08:25:39 -08:00
Kenneth Kehl
5c6b4132a9 try to remove comments 2025-02-06 08:10:15 -08:00
Kenneth Kehl
23e10b1529 tuple 2025-02-05 10:56:32 -08:00
Kenneth Kehl
545bf10e0d tuple 2025-02-05 10:47:25 -08:00
Kenneth Kehl
12a2290ea9 dynamic scan warnings 2025-02-05 10:35:30 -08:00
Kenneth Kehl
bd619af421 merge from main 2025-02-03 09:01:12 -08:00
Beverly Nguyen
2d896daa0e Merge branch 'main' into 2171-clean-up-titles 2025-01-30 10:24:54 -08:00
Beverly Nguyen
6ccf1bb983 fixed arrived from preview page 2025-01-30 10:24:11 -08:00
Beverly Nguyen
5020964fb1 height more visible for stacked bars 2025-01-30 09:56:53 -08:00
Beverly Nguyen
5f8d5996aa cleaning up dup codes 2025-01-29 18:23:26 -08:00
Beverly Nguyen
229842b8c9 pluralization and fixing conditionals 2025-01-29 16:32:21 -08:00
Kenneth Kehl
4feace4cdc code review feedback 2025-01-29 13:51:17 -08:00
Kenneth Kehl
48b317ed52 format 2025-01-29 13:49:58 -08:00
Kenneth Kehl
709b7049c6 code review feedback 2025-01-29 13:22:22 -08:00
Kenneth Kehl
9630d085f4 Update .github/workflows/checks.yml
Co-authored-by: Carlo Costino <ccostino@users.noreply.github.com>
2025-01-29 13:21:28 -08:00
Kenneth Kehl
5d565ab88b fix black and isort forever 2025-01-22 13:45:42 -08:00
Kenneth Kehl
cfb966ce53 redis report 2025-01-22 13:34:34 -08:00
Kenneth Kehl
a4f6dd7100 redis report 2025-01-22 08:44:34 -08:00
Jonathan Bobel
fafc1a1bfb Merge branch 'main' of https://github.com/GSA/notifications-admin into 2200-contextual-tooltips 2025-01-20 14:41:15 -05:00
Jonathan Bobel
935c5fd62c Adding sr-only context to the tooltip 2025-01-17 13:54:13 -05:00
Jonathan Bobel
565e6ad509 2200 - Adding tooltip to Total messages header for explanation 2025-01-17 13:38:36 -05:00
140 changed files with 3148 additions and 2828 deletions

View File

@@ -127,16 +127,6 @@
}
],
"results": {
".github/workflows/checks.yml": [
{
"type": "Secret Keyword",
"filename": ".github/workflows/checks.yml",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 68,
"is_secret": false
}
],
"app/assets/js/uswds.min.js": [
{
"type": "Secret Keyword",
@@ -161,7 +151,7 @@
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 120,
"line_number": 118,
"is_secret": false
}
],
@@ -527,7 +517,7 @@
"filename": "tests/app/main/views/test_accept_invite.py",
"hashed_secret": "07f0a6c13923fc3b5f0c57ffa2d29b715eb80d71",
"is_verified": false,
"line_number": 643,
"line_number": 631,
"is_secret": false
}
],
@@ -684,5 +674,5 @@
}
]
},
"generated_at": "2025-01-16T16:38:48Z"
"generated_at": "2025-03-20T18:22:36Z"
}

View File

@@ -10,7 +10,7 @@ env:
FLASK_APP: application.py
WERKZEUG_DEBUG_PIN: off
REDIS_ENABLED: 0
NODE_VERSION: 16.15.1
NODE_VERSION: 22.3.0
AWS_US_TOLL_FREE_NUMBER: "+18556438890"
ADMIN_BASE_URL: http://localhost:6012
@@ -38,10 +38,10 @@ jobs:
output: report-markdown
annotations: failed-tests
prnumber: ${{ steps.findPr.outputs.number }}
- name: Run style checks
run: poetry run flake8 .
- name: Check imports alphabetized
run: poetry run isort --check-only ./app ./tests
- name: Run style checks
run: poetry run flake8 .
- name: Check dead code
run: make dead-code
- name: Run js tests
@@ -51,73 +51,75 @@ jobs:
- name: Check coverage threshold
run: poetry run coverage report --fail-under=90
end-to-end-tests:
if: ${{ github.actor != 'dependabot[bot]' }}
# TODO FIX THIS!
# end-to-end-tests:
# if: ${{ github.actor != 'dependabot[bot]' }}
permissions:
checks: write
pull-requests: write
contents: write
runs-on: ubuntu-latest
environment: staging
services:
postgres:
image: postgres
env:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: test_notification_api
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 6379 on service container to the host
- 6379:6379
# permissions:
# checks: write
# pull-requests: write
# contents: write
# runs-on: ubuntu-latest
# environment: staging
# services:
# postgres:
# image: postgres
# env:
# POSTGRES_USER: user
# POSTGRES_PASSWORD: password
# POSTGRES_DB: test_notification_api
# options: >-
# --health-cmd pg_isready
# --health-interval 10s
# --health-timeout 5s
# --health-retries 5
# ports:
# # Maps tcp port 5432 on service container to the host
# - 5432:5432
# redis:
# image: redis
# options: >-
# --health-cmd "redis-cli ping"
# --health-interval 10s
# --health-timeout 5s
# --health-retries 5
# ports:
# # Maps tcp port 6379 on service container to the host
# - 6379:6379
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- uses: jwalton/gh-find-current-pr@v1
id: findPr
- name: Check API Server availability
run: |
curl --fail -v https://notify-api-staging.app.cloud.gov || exit 1
- name: Run Admin server
# If we want to log stuff and see what's broken,
# insert this line:
# tail -f admin-server.log &
# above make e2e-test
# steps:
# - uses: actions/checkout@v4
# - uses: ./.github/actions/setup-project
# - uses: jwalton/gh-find-current-pr@v1
# id: findPr
# - name: Check API Server availability
# run: |
# curl --fail -v https://notify-api-staging.app.cloud.gov || exit 1
# - name: Run Admin server
# # If we want to log stuff and see what's broken,
# # insert this line:
# # tail -f admin-server.log &
# # above make e2e-test
run: |
make run-flask > admin-server.log 2>&1 &
tail -f admin-server.log &
make e2e-test
# run: |
# make run-flask > admin-server.log 2>&1 &
# tail -f admin-server.log &
# make e2e-test
# env:
# API_HOST_NAME: https://notify-api-staging.app.cloud.gov/
# SECRET_KEY: ${{ secrets.SECRET_KEY }}
# DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
# ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
# ADMIN_CLIENT_USERNAME: notify-admin
# NOTIFY_ENVIRONMENT: e2etest
# NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }}
# NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
# NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
# NOTIFY_E2E_TEST_URI: http://localhost:6012/
# VCAP_SERVICES: ${{ secrets.VCAP_SERVICES }}
env:
API_HOST_NAME: https://notify-api-staging.app.cloud.gov/
SECRET_KEY: ${{ secrets.SECRET_KEY }}
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: notify-admin
NOTIFY_ENVIRONMENT: e2etest
NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }}
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
NOTIFY_E2E_TEST_URI: http://localhost:6012/
VCAP_SERVICES: ${{ secrets.VCAP_SERVICES }}
validate-new-relic-config:
runs-on: ubuntu-latest
environment: staging
@@ -139,7 +141,7 @@ jobs:
- uses: ./.github/actions/setup-project
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- uses: pypa/gh-action-pip-audit@v1.0.8
- uses: pypa/gh-action-pip-audit@v1.1.0
with:
inputs: requirements.txt
ignore-vulns: |
@@ -165,7 +167,6 @@ jobs:
run: make run-flask &
env:
NOTIFY_ENVIRONMENT: scanning
FEATURE_ABOUT_PAGE_ENABLED: true
- name: Run OWASP Baseline Scan
uses: zaproxy/action-baseline@v0.14.0
with:
@@ -177,7 +178,7 @@ jobs:
cmd_options: "-I"
a11y-scan:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project

View File

@@ -16,7 +16,7 @@ env:
FLASK_APP: application.py
WERKZEUG_DEBUG_PIN: off
REDIS_ENABLED: 0
NODE_VERSION: 16.15.1
NODE_VERSION: 22.3.0
jobs:
dependency-audits:
@@ -26,7 +26,7 @@ jobs:
- uses: ./.github/actions/setup-project
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- uses: pypa/gh-action-pip-audit@v1.0.6
- uses: pypa/gh-action-pip-audit@v1.1.0
with:
inputs: requirements.txt
- name: Run npm audit

View File

@@ -16,23 +16,21 @@ jobs:
with:
fetch-depth: 2
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v44
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
files: |
terraform/demo/**
terraform/shared/**
.github/workflows/deploy-demo.yml
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/demo
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
run: terraform init
- name: Terraform apply
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/demo
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
@@ -91,16 +89,7 @@ jobs:
--var LOGIN_PEM="$LOGIN_PEM"
--strategy rolling
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v44
with:
files: |
deploy-config/egress_proxy/notify-admin-demo.*.acl
.github/actions/deploy-proxy/action.yml
.github/workflows/deploy-demo.yml
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
env:
CF_USERNAME: ${{ secrets.CLOUDGOV_USERNAME }}

View File

@@ -16,23 +16,21 @@ jobs:
with:
fetch-depth: 2
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v44
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
files: |
terraform/production/**
terraform/shared/**
.github/workflows/deploy-prod.yml
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/production
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
run: terraform init
- name: Terraform apply
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/production
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
@@ -91,16 +89,7 @@ jobs:
--var LOGIN_PEM="$LOGIN_PEM"
--strategy rolling
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v44
with:
files: |
deploy-config/egress_proxy/notify-admin-production.*.acl
.github/actions/deploy-proxy/action.yml
.github/workflows/deploy-prod.yml
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
env:
CF_USERNAME: ${{ secrets.CLOUDGOV_USERNAME }}

View File

@@ -21,23 +21,21 @@ jobs:
with:
fetch-depth: 2
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v44
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
files: |
terraform/staging/**
terraform/shared/**
.github/workflows/deploy.yml
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/staging
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
run: terraform init
- name: Terraform apply
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/staging
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
@@ -98,16 +96,7 @@ jobs:
--strategy rolling
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v44
with:
files: |
deploy-config/egress_proxy/notify-admin-staging.*.acl
.github/actions/deploy-proxy/action.yml
.github/workflows/deploy.yml
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
env:
CF_USERNAME: ${{ secrets.CLOUDGOV_USERNAME }}

View File

@@ -15,6 +15,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Check for drift
uses: dflook/terraform-check@v1
env:
@@ -35,6 +43,14 @@ jobs:
with:
ref: 'production'
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Check for drift
uses: dflook/terraform-check@v1
env:
@@ -55,6 +71,14 @@ jobs:
with:
ref: 'production'
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Check for drift
uses: dflook/terraform-check@v1
env:

View File

@@ -18,6 +18,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Terraform format
id: format
run: terraform fmt -check
@@ -51,7 +59,7 @@ jobs:
# inspiration: https://learn.hashicorp.com/tutorials/terraform/github-actions#review-actions-workflow
- name: Update PR
uses: actions/github-script@v6
uses: actions/github-script@v7
# we would like to update the PR even when a prior step failed
if: ${{ always() }}
with:

View File

@@ -18,6 +18,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Terraform format
id: format
run: terraform fmt -check
@@ -51,7 +59,7 @@ jobs:
# inspiration: https://learn.hashicorp.com/tutorials/terraform/github-actions#review-actions-workflow
- name: Update PR
uses: actions/github-script@v6
uses: actions/github-script@v7
# we would like to update the PR even when a prior step failed
if: ${{ always() }}
with:

View File

@@ -18,6 +18,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
# Looks like we need to install Terraform ourselves now!
# https://github.com/actions/runner-images/issues/10796#issuecomment-2417064348
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "^1.7.5"
terraform_wrapper: false
- name: Terraform format
id: format
run: terraform fmt -check
@@ -51,7 +59,7 @@ jobs:
# inspiration: https://learn.hashicorp.com/tutorials/terraform/github-actions#review-actions-workflow
- name: Update PR
uses: actions/github-script@v6
uses: actions/github-script@v7
# we would like to update the PR even when a prior step failed
if: ${{ always() }}
with:

4
.gitignore vendored
View File

@@ -15,6 +15,10 @@
## Non user files allowed to be commited
!app/assets/pdf/tcpa_overview.pdf
!app/assets/pdf/investing-notifications-tts-public-benefits-memo.pdf
!app/assets/pdf/out-of-pilot-announcement.pdf
!app/assets/pdf/studio-research-snapshot-2022-07-external.pdf
!app/assets/pdf/TCPA-Overview.pdf
!tests/test_pdf_files/no_eof_marker.pdf
!tests/test_pdf_files/multi_page_pdf.pdf
!tests/test_pdf_files/big.pdf

View File

@@ -1,7 +1,10 @@
{
"defaults": {
"standard": "WCAG2AA",
"runners": ["htmlcs"],
"runners": ["htmlcs"],
"chromeLaunchConfig": {
"executablePath": "/usr/bin/google-chrome"
},
"concurrency": 1,
"hideElements": [
"nav > ol a",

View File

@@ -62,6 +62,13 @@ py-lint: ## Run python linting scanners and black
poetry run flake8 .
poetry run isort --check-only ./app ./tests
.PHONY: tada
tada: ## Run python linting scanners and black
poetry run isort ./app ./tests
poetry run black .
poetry run flake8 .
.PHONY: avg-complexity
avg-complexity:
echo "*** Shows average complexity in radon of all code ***"
@@ -155,3 +162,8 @@ upload-static:
# @cf map-route notify-admin ${DNS_NAME} --hostname www
# @cf unmap-route notify-admin-failwhale ${DNS_NAME} --hostname www
# @echo "Failwhale is disabled"
.PHONY: test-single
test-single: export NEW_RELIC_ENVIRONMENT=test
test-single: ## Run a single test file
poetry run pytest $(TEST_FILE)

View File

@@ -1,5 +1,6 @@
import os
import pathlib
import re
import secrets
from functools import partial
from time import monotonic
@@ -168,14 +169,15 @@ def _csp(config):
def create_app(application):
@application.context_processor
def inject_feature_flags():
feature_about_page_enabled = application.config.get(
"FEATURE_ABOUT_PAGE_ENABLED", False
)
return dict(
FEATURE_ABOUT_PAGE_ENABLED=feature_about_page_enabled,
)
# @application.context_processor
# def inject_feature_flags():
# this is where feature flags can be easily added as a dictionary within context
# feature_about_page_enabled = application.config.get(
# "FEATURE_ABOUT_PAGE_ENABLED", False
# )
# return dict(
# FEATURE_ABOUT_PAGE_ENABLED=feature_about_page_enabled,
# )
@application.context_processor
def inject_initial_signin_url():
@@ -616,6 +618,8 @@ def setup_event_handlers():
def add_template_filters(application):
application.add_template_filter(slugify)
for fn in [
format_auth_type,
format_billions,
@@ -673,3 +677,10 @@ def init_jinja(application):
]
jinja_loader = jinja2.FileSystemLoader(template_folders)
application.jinja_loader = jinja_loader
def slugify(text):
"""
Converts text to lowercase, replaces spaces with hyphens, and removes invalid characters.
"""
return re.sub(r"[^a-z0-9-]", "", re.sub(r"\s+", "-", text.lower()))

View File

@@ -19,7 +19,7 @@
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicon-16x16.png">
<link rel="manifest" href="{{ asset_url('images/site.webmanifest') }}">
<link rel="stylesheet" media="screen" href="/static/stylesheets/legacy/uk.css?d077f86473501ab244de0b30600536ee" />
<link rel="stylesheet" media="screen" href="/static/stylesheets/main.css?d077f86473501ab244de0b30600536ee" />
<link rel="stylesheet" media="print" href="/static/stylesheets/print.css?28010888ca5719dc83d7c2c80f6ed2b2" />
<meta property="og:image" content="/static/images/notify-og-image.png">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 KiB

View File

@@ -130,11 +130,12 @@
.append('g')
.attr('class', 'bar-group')
.attr('fill', d => color(d.key));
const minBarHeight = 5;
barGroups.selectAll('rect')
.data(d => d)
.enter()
.append('rect')
.filter(d => d[1] - d[0] > 0)
.attr('x', d => x(d.data.label))
.attr('y', height)
.attr('height', 0)
@@ -155,8 +156,10 @@
.transition()
.duration(1000)
.attr('y', d => y(d[1]))
.attr('height', d => y(d[0]) - y(d[1]));
};
.attr('height', d => {
const calculatedHeight = y(d[0]) - y(d[1]);
return calculatedHeight < minBarHeight ? minBarHeight : calculatedHeight;
}); };
// Function to create an accessible table
const createTable = function(tableId, chartType, labels, deliveredData, failedData, pendingData) {
@@ -213,7 +216,13 @@
return;
}
var url = type === 'service' ? `/services/${currentServiceId}/daily-stats.json` : `/services/${currentServiceId}/daily-stats-by-user.json`;
var userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
var url = type === 'service'
? `/services/${currentServiceId}/daily-stats.json?timezone=${encodeURIComponent(userTimezone)}`
: `/services/${currentServiceId}/daily-stats-by-user.json?timezone=${encodeURIComponent(userTimezone)}`;
return fetch(url)
.then(response => {
if (!response.ok) {
@@ -238,9 +247,6 @@
failedData.push(data[dateString].sms.failure);
pendingData.push(data[dateString].sms.pending || 0);
totalMessages += data[dateString].sms.delivered + data[dateString].sms.failure + data[dateString].sms.pending;
// Calculate the total number of messages
totalMessages += data[dateString].sms.delivered + data[dateString].sms.failure;
}
}

View File

@@ -13,16 +13,23 @@
} else {
$submitButton.data('clicked', 'true');
setTimeout(renableSubmitButton($submitButton), 1500);
if ($submitButton.is('[name="Send"], [name="Schedule"]')) {
$submitButton.prop('disabled', true);
setTimeout(() => {
renableSubmitButton($submitButton);
}, 10000);
} else {
setTimeout(renableSubmitButton($submitButton), 1500);
}
}
};
let renableSubmitButton = $submitButton => () => {
$submitButton.data('clicked', '');
$submitButton.prop('disabled', false);
};
$('form').on('submit', disableSubmitButtons);

View File

@@ -6,17 +6,17 @@
var chartTitle = document.getElementById('chartTitle').textContent;
// Access data attributes from the HTML
var sms_sent = parseInt(chartContainer.getAttribute('data-sms-sent'));
var sms_remaining_messages = parseInt(chartContainer.getAttribute('data-sms-allowance-remaining'));
var totalMessages = sms_sent + sms_remaining_messages;
var messagesSent = parseInt(chartContainer.getAttribute('data-messages-sent'));
var messagesRemaining = parseInt(chartContainer.getAttribute('data-messages-remaining'));
var totalMessages = messagesSent + messagesRemaining;
// Update the message below the chart
document.getElementById('message').innerText = `${sms_sent.toLocaleString()} sent / ${sms_remaining_messages.toLocaleString()} remaining`;
document.getElementById('message').innerText = `${messagesSent.toLocaleString()} sent / ${messagesRemaining.toLocaleString()} remaining`;
// Calculate minimum width for "Messages Sent" as 1% of the total chart width
var minSentPercentage = (sms_sent === 0) ? 0 : 0.02;
var minSentPercentage = (messagesSent === 0) ? 0 : 0.02;
var minSentValue = totalMessages * minSentPercentage;
var displaySent = Math.max(sms_sent, minSentValue);
var displaySent = Math.max(messagesSent, minSentValue);
var displayRemaining = totalMessages - displaySent;
var svg = d3.select("#totalMessageChart");
@@ -48,7 +48,7 @@
.attr("width", 0) // Start with width 0 for animation
.on('mouseover', function(event) {
tooltip.style('display', 'block')
.html(`Messages Sent: ${sms_sent.toLocaleString()}`);
.html(`Messages Sent: ${messagesSent.toLocaleString()}`);
})
.on('mousemove', function(event) {
tooltip.style('left', `${event.pageX + 10}px`)
@@ -66,7 +66,7 @@
.attr("width", 0) // Start with width 0 for animation
.on('mouseover', function(event) {
tooltip.style('display', 'block')
.html(`Remaining: ${sms_remaining_messages.toLocaleString()}`);
.html(`Remaining: ${messagesRemaining.toLocaleString()}`);
})
.on('mousemove', function(event) {
tooltip.style('left', `${event.pageX + 10}px`)
@@ -115,9 +115,9 @@
var tbodyRow = document.createElement('tr');
var tdMessagesSent = document.createElement('td');
tdMessagesSent.textContent = sms_sent.toLocaleString(); // Value for Messages Sent
tdMessagesSent.textContent = messagesSent.toLocaleString(); // Value for Messages Sent
var tdRemaining = document.createElement('td');
tdRemaining.textContent = sms_remaining_messages.toLocaleString(); // Value for Remaining
tdRemaining.textContent = messagesRemaining.toLocaleString(); // Value for Remaining
tbodyRow.appendChild(tdMessagesSent);
tbodyRow.appendChild(tdRemaining);

View File

@@ -0,0 +1,115 @@
function showError(input, errorElement, message) {
errorElement.textContent = ""; // Clear existing message
errorElement.style.display = "block";
// Small delay to ensure screen readers pick up the change
setTimeout(() => {
errorElement.textContent = message;
}, 10);
if (input.type !== "radio" && input.type !== "checkbox") {
input.classList.add("usa-input--error");
}
input.setAttribute("aria-describedby", errorElement.id);
}
function hideError(input, errorElement) {
errorElement.style.display = "none";
if (input.type !== "radio" && input.type !== "checkbox") {
input.classList.remove("usa-input--error");
}
input.removeAttribute("aria-describedby");
}
function getFieldLabel(input) {
const label = document.querySelector(`label[for="${input.id}"]`);
return label ? label.textContent.trim() : "This field";
}
// Attach validation logic to forms
function attachValidation() {
const forms = document.querySelectorAll('form[data-force-focus="True"]');
forms.forEach((form) => {
const inputs = form.querySelectorAll("input, textarea, select");
form.addEventListener("submit", function (event) {
let isValid = true;
let firstInvalidInput = null;
const validatedRadioNames = new Set();
inputs.forEach((input) => {
const errorId = input.type === "radio" ? `${input.name}-error` : `${input.id}-error`;
let errorElement = document.getElementById(errorId);
if (!errorElement) {
errorElement = document.createElement("span");
errorElement.id = errorId;
errorElement.classList.add("usa-error-message");
errorElement.setAttribute("aria-live", "polite");
errorElement.style.display = "none";
if (input.type === "radio") {
const group = form.querySelectorAll(`input[name="${input.name}"]`);
const lastRadio = group[group.length - 1];
lastRadio.parentElement.insertAdjacentElement("afterend", errorElement);
} else {
input.insertAdjacentElement("afterend", errorElement);
}
}
if (input.type === "radio") {
if (validatedRadioNames.has(input.name)) return;
validatedRadioNames.add(input.name);
const radioGroup = form.querySelectorAll(`input[name="${input.name}"]`);
const isChecked = Array.from(radioGroup).some(radio => radio.checked);
if (!isChecked) {
showError(input, errorElement, `Error: A selection must be made.`);
isValid = false;
if (!firstInvalidInput) {
firstInvalidInput = input;
}
}
} else if (input.value.trim() === "") {
showError(input, errorElement, `Error: ${getFieldLabel(input)} is required.`);
isValid = false;
if (!firstInvalidInput) {
firstInvalidInput = input;
}
}
});
if (!isValid) {
event.preventDefault();
if (firstInvalidInput) firstInvalidInput.focus();
}
});
inputs.forEach((input) => {
input.addEventListener("input", function () {
const errorId = input.type === "radio" ? `${input.name}-error` : `${input.id}-error`;
const errorElement = document.getElementById(errorId);
if (errorElement && input.value.trim() !== "") {
hideError(input, errorElement);
}
});
if (input.type === "radio") {
input.addEventListener("change", function () {
const errorElement = document.getElementById(`${input.name}-error`);
if (errorElement) {
hideError(input, errorElement);
}
});
}
});
});
}
// Automatically attach validation only in the browser
if (typeof window !== "undefined") {
document.addEventListener("DOMContentLoaded", attachValidation);
}
// ✅ Check if we're in a Node.js environment (for Jest) before using `module.exports`
if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
module.exports = { showError, hideError, getFieldLabel, attachValidation };
}

Binary file not shown.

Binary file not shown.

View File

@@ -1,186 +0,0 @@
@use "uswds-core" as *;
.dashboard {
.big-number-with-status {
.big-number-smaller {
display: flex;
flex-direction: column;
.big-number-number {
font-size: units(5);
line-height: units(5);
}
.big-number-label {
font-size: units(2.5);
}
}
.big-number-status {
background: color('green-cool-40v');
display: flex;
padding: units(1) units(2);
&--failing {
padding: 0;
a.usa-link {
color: white;
background: color('red-warm-50v');
padding: units(1) units(2);
margin: 0;
width: 100%;
&:hover {
background: color('red-warm-60v');
}
}
}
}
}
.usa-table {
width: 100%;
caption {
margin-bottom: 0;
}
.table-field-center-aligned {
text-align: center;
}
.template-statistics-table-template-name {
padding-left: units(4);
display: inline-block;
background-repeat: no-repeat;
background-image: url(../img/material-icons/description.svg);
}
}
.get-started {
border: 1px solid color('gray-90');
padding: units(2);
margin-bottom: units(4);
}
}
.dashboard-table {
table {
width: 100%;
}
.file-list-filename {
font-weight: bold;
}
.file-list-hint {
margin: 0;
word-break: break-word;
}
.table-field,
.table-field-right-aligned {
width: 50%;
}
&.usage-table {
.table-field,
.table-field-left-aligned,
.table-field-right-aligned {
width: auto;
}
}
}
.job-status-table {
table-layout: fixed;
thead tr th {
border-bottom: 0;
}
thead,
tbody,
tr {
width: 100%;
}
th:first-child,
td:first-child {
width: 75%;
}
th:nth-child(2),
R td:nth-child(2) {
width: 25%;
}
}
.usage-table {
ul {
list-style: none;
padding: 0;
margin: 0;
}
.big-number-smallest {
display: flex;
flex-direction: column;
}
}
.job-table {
width: 100%;
border-collapse: collapse;
td.file-name {
width: 25%;
overflow-wrap: anywhere;
}
td.jobid {
width: 5%;
}
td.template {
width: 25%;
}
td.time-sent {
width: 15%;
}
td.sender {
width: 20%;
overflow-wrap: break-word;
}
td.count-of-recipients {
width: 5%;
}
td.report {
width: 2%;
text-align: center;
}
td.delivered {
width: 2%;
text-align: center;
}
td.failed {
width: 2%;
text-align: center;
}
td.report img {
padding-top: 5px;
}
th {
padding: 0.5rem 1rem;
}
}
@media (max-width: 768px) {
.usa-table-container--scrollable-mobile {
margin: 0;
overflow-y: hidden;
}
}
.usa-table th[data-sortable][aria-sort='ascending'],
.usa-table th[data-sortable][aria-sort='descending'] {
background-color: #a1d3ff;
}
#template-list {
max-height: 500px;
overflow-y: auto;
padding: units(1) 0 units(1) units(1);
margin: units(2) 0 units(5);
ul {
padding: 0;
margin: 0;
list-style: none;
}
}
.usa-prose > p.max-width-full {
max-width: 100%;
}

View File

@@ -60,17 +60,6 @@ $failed: color('gray-cool-20');
}
}
.usa-tooltip {
line-height: 1;
.usa-tooltip__body {
width: units(mobile);
font-size: size("body", 2);
height: auto;
white-space: wrap;
line-height: units(1);
}
}
.progress-bar {
width: 300px;
height: 20px;

View File

@@ -1,81 +0,0 @@
@use 'uswds-core' as *;
$do-dont-color-do: 'green-cool-50v';
$do-dont-color-dont: 'red-cool-50v';
$do-dont-color-border: 'gray-cool-20';
$do-dont-padding: 3;
$do-dont-top-bar-width: 1;
.do-dont {
display: flex;
height: 100%;
padding-top: units(2);
}
.do-dont__do,
.do-dont__dont {
background-color: color('white');
border: 1px solid color($do-dont-color-border);
flex: 1 0 0;
height: 100%;
position: relative;
}
.do-dont__do {
padding: 0rem;
}
.do-dont__do:before,
.do-dont__dont:before {
content: '';
position: absolute;
height: units($do-dont-top-bar-width);
width: calc(100% + 2px);
top: -1px;
left: -1px;
}
.do-dont__do:before {
background-color: color($do-dont-color-do);
}
.do-dont__dont:before {
background-color: color($do-dont-color-dont);
}
.do-dont__heading {
// @include typeset("lang", "lg", 2);
align-items: center;
border-bottom: 1px solid color($do-dont-color-border);
display: flex;
font-weight: fw('bold');
margin: 0;
padding: units(4) units($do-dont-padding) units($do-dont-padding);
.usa-icon {
@include u-square(3);
margin-right: units(0.5);
}
}
.do-dont__do .do-dont__heading {
color: color($do-dont-color-do);
}
.do-dont__dont .do-dont__heading {
color: color($do-dont-color-dont);
}
.do-dont__content {
padding: 0 units($do-dont-padding) units($do-dont-padding)
units($do-dont-padding);
ul {
margin-bottom: 0;
overflow-wrap: anywhere;
}
li + li {
margin-top: units(1);
}
}

View File

@@ -1,79 +0,0 @@
@use "uswds-core" as *;
@use "tokens" as vars;
.usa-section--dark {
background-color: color('gray-90');
h1 {
font-family: family('sans');
font-size: units(7);
color: vars.$notify-light-blue;
@media (max-width: units('desktop')) {
font-size: units(5);
}
}
}
.usa-hero > .grid-container {
@media (max-width: units('tablet')) {
padding-top: 1rem;
padding-bottom: 1rem;
}
}
.usa-section {
&.key-features {
background-color: color('gray-cool-2');
}
&.security-and-privacy {
img {
filter: brightness(0) saturate(100%) invert(22%) sepia(98%) saturate(1829%) hue-rotate(187deg) brightness(88%) contrast(101%);
}
}
&__home {
h2 {
font-size: units(6);
line-height: 1.2;
@media (max-width: units('desktop')) {
font-size: units(4);
}
}
p {
font-size: 20px;
}
img {
@media (max-width: units('tablet')) {
max-width: 60%;
}
}
}
}
.home-cards {
justify-content: space-between;
.usa-card__container {
align-items: center;
text-align: center;
overflow: hidden;
border: 0;
background-color: transparent;
.img-container {
width: units('card');
height: units('card');
margin: units(3) 0;
border-radius: 50%;
background: color('gray-cool-10');
display: flex;
align-items: center;
justify-content: center;
img {
width: units(10);
height: units(10);
filter: brightness(0) saturate(100%) invert(22%) sepia(98%) saturate(1829%) hue-rotate(187deg) brightness(88%) contrast(101%);
}
}
h3, p {
font-size: units(3);
line-height: 1.3;
}
}
}

View File

@@ -1,35 +0,0 @@
@use "uswds-core" as *;
// Tabs
.tabs {
.pill {
display: flex;
list-style: none;
padding: 0;
.pill-item__container {
border: 1px solid color('gray-cool-10');
flex: 1;
display: flex;
flex-direction: column;
text-align: center;
font-size: units(2);
a {
padding: units(4);
.big-number-smaller {
font-size: units(5);
line-height: units(6);
}
.big-number-smallest {
font-size: units(3);
}
&:not(.pill-item--selected):hover {
background: color('blue-warm-70v');
}
&.pill-item--selected:hover {
color: color('blue-60v');
}
}
}
}
}

View File

@@ -1,8 +0,0 @@
@use "uswds-core" as *;
// Colors
$notify-primary: color('blue-60v');
$notify-secondary: color('red-warm-50v');
$notify-light-blue: color('blue-40v');
$notify-tertiary: color('gold-20v');
$notify-text: color('ink');

View File

@@ -1,3 +1,25 @@
/*
* * * * * ==============================
* * * * * ==============================
* * * * * ==============================
* * * * * ==============================
========================================
========================================
========================================
----------------------------------------
USWDS THEME CUSTOM STYLES
----------------------------------------
!! Copy this file to your project's
sass root. Don't edit the version
in node_modules.
----------------------------------------
Custom project SASS goes here.
i.e.
@include u-padding-right('05');
----------------------------------------
*/
@use 'uswds-core' as *;
iframe:focus,
@@ -34,10 +56,7 @@ button:not([disabled]):focus {
}
}
@include at-media-max('desktop') {
.usa-nav__secondary-links
{
padding-left: units(2);
}
padding: 0 units(2);
ul li {
padding-bottom: units(1);
}
@@ -120,11 +139,6 @@ td.table-empty-message {
font-family: family('sans');
}
.usa-dark-background .pill-item__label {
color: white;
text-decoration: none !important;
}
.pill-item.usa-link {
text-decoration: none !important;
}
@@ -141,17 +155,9 @@ td.table-empty-message {
}
}
.login-button {
margin-right: 0;
img {
height: 1rem;
}
@media (max-width: units('desktop')) {
img {
height: 14px;
}
font-size: 14px;
}
.usa-button img {
margin-left: 0.5rem;
height: 1rem;
}
.usa-button.login-button.login-button--primary,
@@ -187,9 +193,6 @@ td.table-empty-message {
word-wrap: break-word;
}
// border: 1px solid color('gray-cool-10');
// padding: units(2);
.tick-cross-list-permissions {
margin: units(1) 0;
padding-left: units(2);
@@ -246,6 +249,11 @@ td.table-empty-message {
}
}
.usa-checkbox.template-list-item.template-list-item-with-checkbox.template-list-item-without-ancestors {
display: flex;
flex-direction: column;
}
.usa-checkbox__label-description {
margin: units(2px) 0 units(1) units(4);
}
@@ -277,7 +285,8 @@ td.table-empty-message {
@include u-width('mobile-lg');
margin-top: units(2);
}
input#search {
input#search-by-name {
margin-top: units(1);
width: 100%;
border: 1px solid color('gray-60');
}
@@ -354,7 +363,258 @@ td.table-empty-message {
}
}
// Etc
// Dashboard
.dashboard {
.big-number-with-status {
.big-number-smaller {
display: flex;
flex-direction: column;
.big-number-number {
font-size: units(5);
line-height: units(5);
}
.big-number-label {
font-size: units(2.5);
}
}
.big-number-status {
background: color('green-cool-40v');
display: flex;
padding: units(1) units(2);
&--failing {
padding: 0;
a.usa-link {
color: white;
background: color('red-warm-50v');
padding: units(1) units(2);
margin: 0;
width: 100%;
&:hover {
background: color('red-warm-60v');
}
}
}
}
}
.usa-table {
width: 100%;
caption {
margin-bottom: 0;
}
.table-field-center-aligned {
text-align: center;
}
.template-statistics-table-template-name {
padding-left: units(4);
display: inline-block;
background-repeat: no-repeat;
background-image: url(../img/material-icons/description.svg);
}
}
.get-started {
border: 1px solid color('gray-90');
padding: units(2);
margin-bottom: units(4);
}
}
.dashboard-table {
table {
width: 100%;
}
.file-list-filename {
font-weight: bold;
}
.file-list-hint {
margin: 0;
word-break: break-word;
}
.table-field,
.table-field-right-aligned {
width: 50%;
}
&.usage-table {
.table-field,
.table-field-left-aligned,
.table-field-right-aligned {
width: auto;
}
}
}
.job-status-table {
table-layout: fixed;
thead tr th {
border-bottom: 0;
}
thead,
tbody,
tr {
width: 100%;
}
th:first-child,
td:first-child {
width: 75%;
}
th:nth-child(2),
R td:nth-child(2) {
width: 25%;
}
}
.usage-table {
ul {
list-style: none;
padding: 0;
margin: 0;
}
.big-number-smallest {
display: flex;
flex-direction: column;
}
}
.job-table {
width: 100%;
border-collapse: collapse;
td.file-name {
width: 25%;
overflow-wrap: anywhere;
}
td.jobid {
width: 5%;
}
td.template {
width: 25%;
}
td.time-sent {
width: 15%;
}
td.sender {
width: 20%;
overflow-wrap: break-word;
}
td.count-of-recipients {
width: 5%;
}
td.report {
width: 2%;
text-align: center;
}
td.delivered {
width: 2%;
text-align: center;
}
td.failed {
width: 2%;
text-align: center;
}
td.report img {
padding-top: 5px;
}
th {
padding: 0.5rem 1rem;
}
}
@media (max-width: 768px) {
.usa-table-container--scrollable-mobile {
margin: 0;
overflow-y: hidden;
}
}
.usa-table th[data-sortable][aria-sort='ascending'],
.usa-table th[data-sortable][aria-sort='descending'] {
background-color: #a1d3ff;
}
#template-list {
max-height: 500px;
overflow-y: auto;
padding: units(1) 0 units(1) units(1);
margin: units(2) 0 units(5);
ul {
padding: 0;
margin: 0;
list-style: none;
}
}
.usa-prose > p.max-width-full {
max-width: 100%;
}
.usa-tooltip {
&__information {
background: color('ink');
margin-top: 4px;
color: white;
border-radius: 50%;
height: units(3);
width: units(3);
border: 1px solid color('ink');
}
.usa-tooltip__body {
min-width: units('card-lg');
max-width: units('mobile');
white-space: normal;
word-wrap: break-word;
}
}
// Tabs
.tabs {
.pill {
display: flex;
list-style: none;
padding: 0;
.pill-item__container {
border: 1px solid color('gray-cool-10');
flex: 1;
display: flex;
flex-direction: column;
text-align: center;
font-size: units(2);
a {
padding: units(4);
.big-number-smaller {
font-size: units(5);
line-height: units(6);
}
.big-number-smallest {
font-size: units(3);
}
.pill-item__label {
color: white;
}
&:not(.pill-item--selected):hover {
background: color('blue-warm-70v');
.pill-item__label {
color: white;
}
}
&.pill-item--selected {
.pill-item__label {
color: color('blue-60v');
}
&:hover {
.pill-item__label {
color: color('blue-60v');
}
}
}
}
}
}
}
.email-brand,
.browse-list {
@@ -515,6 +775,86 @@ div.guides {
height: 400px;
}
$do-dont-color-do: 'green-cool-50v';
$do-dont-color-dont: 'red-cool-50v';
$do-dont-color-border: 'gray-cool-20';
$do-dont-padding: 3;
$do-dont-top-bar-width: 1;
.do-dont {
display: flex;
height: 100%;
padding-top: units(2);
}
.do-dont__do,
.do-dont__dont {
background-color: color('white');
border: 1px solid color($do-dont-color-border);
flex: 1 0 0;
height: 100%;
position: relative;
}
.do-dont__do {
padding: 0rem;
}
.do-dont__do:before,
.do-dont__dont:before {
content: '';
position: absolute;
height: units($do-dont-top-bar-width);
width: calc(100% + 2px);
top: -1px;
left: -1px;
}
.do-dont__do:before {
background-color: color($do-dont-color-do);
}
.do-dont__dont:before {
background-color: color($do-dont-color-dont);
}
.do-dont__heading {
// @include typeset("lang", "lg", 2);
align-items: center;
border-bottom: 1px solid color($do-dont-color-border);
display: flex;
font-weight: fw('bold');
margin: 0;
padding: units(4) units($do-dont-padding) units($do-dont-padding);
.usa-icon {
@include u-square(3);
margin-right: units(0.5);
}
}
.do-dont__do .do-dont__heading {
color: color($do-dont-color-do);
}
.do-dont__dont .do-dont__heading {
color: color($do-dont-color-dont);
}
.do-dont__content {
padding: 0 units($do-dont-padding) units($do-dont-padding)
units($do-dont-padding);
ul {
margin-bottom: 0;
overflow-wrap: anywhere;
}
li + li {
margin-top: units(1);
}
}
.site-note {
background-color: #dfe1e2;
max-width: 72ex;
@@ -659,6 +999,32 @@ nav.nav {
}
}
.home-cards {
justify-content: space-between;
.usa-card__container {
align-items: center;
text-align: center;
border-radius: 4px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
img {
margin: units(4) auto 0;
width: units(15);
height: units(15);
}
.usa-card__body {
margin-bottom: units(2);
}
.blue-bar {
background-color: #005eb8;
height: 1.3em;
width: 100%;
margin: 0;
border-radius: 0;
}
}
}
.contact-us-card {
border: 2px solid color("ink");
@@ -690,3 +1056,7 @@ nav.nav {
.form-control-error {
border: 4px solid #b10e1e
}
.usa-site-alert .usa-alert .usa-alert__body {
max-width: 75rem;
}

View File

@@ -1,10 +1,5 @@
@forward "uswds-theme";
@forward "uswds";
@forward "uswds-theme-custom-styles";
@use "tokens" as vars;
@forward "legacy-styles";
@forward "home";
@forward "dashboard";
@forward "tabs";
@forward "do-dont";
@forward "data-visualization";

View File

@@ -0,0 +1,90 @@
// Path to assets for use with file-url()
$path: '/static/images/';
// Dependencies from GOV.UK Frontend Toolkit
// https://github.com/alphagov/govuk_frontend_toolkit/
@import 'conditionals';
@import 'shims';
@import 'measurements';
@import 'css3';
@import 'colours';
@import 'typography';
@import 'grid_layout';
@import 'helpers';
// Dependencies from GOVU.UK Frontend Toolkit, rewritten for this application
@import 'url-helpers';
// Specific to this application, needs to go at the top of the cascade
@import 'globals';
// Dependencies from GOV.UK Elements
// https://github.com/alphagov/govuk_elements
@import 'elements/helpers';
@import 'elements/reset';
@import 'elements/details';
@import 'elements/elements-typography';
@import 'elements/forms';
@import 'elements/forms/form-multiple-choice';
@import 'elements/forms/form-validation';
@import 'elements/lists';
@import 'elements/panels';
@import 'elements/tables';
// Dependencies from GOV.UK Frontend, packaged to be specific to this application
@import './govuk-frontend/all';
// Custom overrides
.govuk-link {
font-weight: bold;
}
// Specific to this application
@import 'local/typography';
@import 'grids';
@import 'components/site-footer';
@import 'components/placeholder';
@import 'components/sms-message';
@import 'components/page-footer';
@import 'components/table';
@import 'components/navigation';
@import 'components/big-number';
@import 'components/banner';
@import 'components/textbox';
@import 'components/file-upload';
@import 'components/browse-list';
@import 'components/email-message';
@import 'components/copy-to-clipboard';
@import 'components/vendor/previous-next-navigation';
@import 'components/radios';
@import 'components/checkboxes';
@import 'components/pill';
@import 'components/show-more';
@import 'components/message';
@import 'components/research-mode';
@import 'components/tick-cross';
@import 'components/list-entry';
@import 'components/live-search';
@import 'components/stick-at-top-when-scrolling';
@import 'components/fullscreen-table';
@import 'components/conditional-radios';
@import 'components/vendor/breadcrumbs';
@import 'components/vendor/responsive-embed';
@import 'components/preview-pane';
@import 'components/task-list';
@import 'components/loading-indicator';
@import 'components/area-list';
@import 'components/content-metadata';
@import 'views/dashboard';
@import 'views/users';
@import 'views/api';
@import 'views/product-page';
@import 'views/template';
@import 'views/notification';
@import 'views/send';
@import 'views/get_started';
@import 'views/history';
// TODO: break this up
@import 'app';

View File

@@ -88,8 +88,6 @@ class Config(object):
],
}
FEATURE_ABOUT_PAGE_ENABLED = getenv("FEATURE_ABOUT_PAGE_ENABLED", "false") == "true"
def _s3_credentials_from_env(bucket_prefix):
return {

View File

@@ -61,7 +61,7 @@ class ValidEmail:
class NoCommasInPlaceHolders:
def __init__(self, message="You cannot put commas between double brackets"):
def __init__(self, message="You cannot put commas between double parenthesis"):
self.message = message
def __call__(self, form, field):
@@ -108,33 +108,17 @@ class OnlySMSCharacters:
)
if non_sms_characters:
raise ValidationError(
"You cannot use {} in {}. {} will not show up properly on everyones phones.".format(
"Please remove the unaccepted character {} in your message, then save again".format(
formatted_list(
non_sms_characters,
conjunction="or",
conjunction="and",
before_each="",
after_each="",
),
{
"sms": "text messages",
}.get(self._template_type),
("It" if len(non_sms_characters) == 1 else "They"),
)
)
# class NoPlaceholders:
# def __init__(self, message=None):
# self.message = message or (
# 'You cant use ((double brackets)) to personalize this message'
# )
# def __call__(self, form, field):
# if Field(field.data).placeholders:
# raise ValidationError(self.message)
class LettersNumbersSingleQuotesFullStopsAndUnderscoresOnly:
regex = re.compile(r"^[a-zA-Z0-9\s\._']+$")

View File

@@ -1,34 +1,25 @@
import calendar
from datetime import datetime
from datetime import datetime, timedelta
from functools import partial
from itertools import groupby
from zoneinfo import ZoneInfo
from flask import Response, abort, jsonify, render_template, request, session, url_for
from flask import abort, jsonify, render_template, request, session, url_for
from flask_login import current_user
from werkzeug.utils import redirect
from app import (
billing_api_client,
current_service,
job_api_client,
service_api_client,
template_statistics_client,
)
from app.formatters import format_date_numeric, format_datetime_numeric
from app.main import main
from app.main.views.user_profile import set_timezone
from app.statistics_utils import get_formatted_percentage
from app.utils import (
DELIVERED_STATUSES,
FAILURE_STATUSES,
REQUESTED_STATUSES,
service_has_permission,
)
from app.utils.csv import Spreadsheet
from app.utils.pagination import generate_next_dict, generate_previous_dict
from app.utils import DELIVERED_STATUSES, FAILURE_STATUSES, REQUESTED_STATUSES
from app.utils.time import get_current_financial_year
from app.utils.user import user_has_permissions
from notifications_utils.recipients import format_phone_number_human_readable
@main.route("/services/<uuid:service_id>/dashboard")
@@ -48,68 +39,111 @@ def service_dashboard(service_id):
if not current_user.has_permissions("view_activity"):
return redirect(url_for("main.choose_template", service_id=service_id))
yearly_usage = billing_api_client.get_annual_usage_for_service(
service_id,
get_current_financial_year(),
)
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(
current_service.id,
)
usage_data = get_annual_usage_breakdown(yearly_usage, free_sms_allowance)
sms_sent = usage_data["sms_sent"]
sms_allowance_remaining = usage_data["sms_allowance_remaining"]
job_response = job_api_client.get_jobs(service_id)["data"]
service_data_retention_days = 7
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)
active_jobs = [job for job in job_response if job["job_status"] != "cancelled"]
sorted_jobs = sorted(active_jobs, key=lambda job: job["created_at"], reverse=True)
job_lists = [
{**job_dict, "finished_processing": job_is_finished(job_dict)}
for job_dict in sorted_jobs
]
total_messages = service_api_client.get_service_message_ratio(service_id)
messages_remaining = total_messages.get("messages_remaining", 0)
messages_sent = total_messages.get("messages_sent", 0)
all_statistics = template_statistics_client.get_template_statistics_for_service(
service_id, limit_days=7
)
template_statistics = aggregate_template_usage(all_statistics)
return render_template(
"views/dashboard/dashboard.html",
updates_url=url_for(".service_dashboard_updates", service_id=service_id),
partials=get_dashboard_partials(service_id),
jobs=sorted_jobs,
jobs=job_lists,
service_data_retention_days=service_data_retention_days,
sms_sent=sms_sent,
sms_allowance_remaining=sms_allowance_remaining,
messages_remaining=messages_remaining,
messages_sent=messages_sent,
template_statistics=template_statistics,
most_used_template_count=max(
[row["count"] for row in template_statistics] or [0]
),
)
def job_is_finished(job_dict):
done_statuses = DELIVERED_STATUSES + FAILURE_STATUSES + ["cancelled"]
processed_count = sum(
stat["count"]
for stat in job_dict["statistics"]
if stat["status"] in done_statuses
)
return job_dict["notification_count"] == processed_count
@main.route("/services/<uuid:service_id>/daily-stats.json")
@user_has_permissions()
def get_daily_stats(service_id):
date_range = get_stats_date_range()
stats = service_api_client.get_service_notification_statistics_by_day(
service_id, start_date=date_range["start_date"], days=date_range["days"]
days = date_range["days"]
user_timezone = request.args.get("timezone", "UTC")
stats_utc = service_api_client.get_service_notification_statistics_by_day(
service_id,
start_date=date_range["start_date"],
days=days,
)
return jsonify(stats)
local_stats = get_local_daily_stats_for_last_x_days(stats_utc, user_timezone, days)
return jsonify(local_stats)
def get_local_daily_stats_for_last_x_days(stats_utc, user_timezone, days):
tz = ZoneInfo(user_timezone)
today_local = datetime.now(tz).date()
start_local = today_local - timedelta(days=days - 1)
# Generate exactly days local dates, each with zeroed stats
days_list = [
(start_local + timedelta(days=i)).strftime("%Y-%m-%d") for i in range(days)
]
aggregator = {
d: {
"sms": {"delivered": 0, "failure": 0, "pending": 0, "requested": 0},
"email": {"delivered": 0, "failure": 0, "pending": 0, "requested": 0},
}
for d in days_list
}
# Convert each UTC timestamp to local date and iterate
for utc_ts, data in stats_utc.items():
utc_dt = datetime.strptime(utc_ts, "%Y-%m-%dT%H:%M:%SZ").replace(
tzinfo=ZoneInfo("UTC")
)
local_day = utc_dt.astimezone(tz).strftime("%Y-%m-%d")
if local_day in aggregator:
for msg_type in ["sms", "email"]:
for status in ["delivered", "failure", "pending", "requested"]:
aggregator[local_day][msg_type][status] += data[msg_type][status]
return aggregator
@main.route("/services/<uuid:service_id>/daily-stats-by-user.json")
@user_has_permissions()
def get_daily_stats_by_user(service_id):
service_id = session.get("service_id")
date_range = get_stats_date_range()
stats = service_api_client.get_user_service_notification_statistics_by_day(
days = date_range["days"]
user_timezone = request.args.get("timezone", "UTC")
stats_utc = service_api_client.get_user_service_notification_statistics_by_day(
service_id,
user_id=current_user.id,
start_date=date_range["start_date"],
days=date_range["days"],
days=days,
)
return jsonify(stats)
@main.route("/services/<uuid:service_id>/dashboard.json")
@user_has_permissions("view_activity")
def service_dashboard_updates(service_id):
return jsonify(**get_dashboard_partials(service_id))
@main.route("/services/<uuid:service_id>/template-activity")
@user_has_permissions("view_activity")
def template_history(service_id):
return redirect(url_for("main.template_usage", service_id=service_id), code=301)
local_stats = get_local_daily_stats_for_last_x_days(stats_utc, user_timezone, days)
return jsonify(local_stats)
@main.route("/services/<uuid:service_id>/template-usage")
@@ -197,103 +231,6 @@ def usage(service_id):
)
@main.route("/services/<uuid:service_id>/monthly")
@user_has_permissions("view_activity")
def monthly(service_id):
year, current_financial_year = requested_and_current_financial_year(request)
return render_template(
"views/dashboard/monthly.html",
months=format_monthly_stats_to_list(
service_api_client.get_monthly_notification_stats(service_id, year)["data"]
),
years=get_tuples_of_financial_years(
partial_url=partial(url_for, ".monthly", service_id=service_id),
start=current_financial_year - 2,
end=current_financial_year,
),
selected_year=year,
)
@main.route("/services/<uuid:service_id>/inbox")
@user_has_permissions("view_activity")
@service_has_permission("inbound_sms")
def inbox(service_id):
return render_template(
"views/dashboard/inbox.html",
partials=get_inbox_partials(service_id),
updates_url=url_for(
".inbox_updates", service_id=service_id, page=request.args.get("page")
),
)
@main.route("/services/<uuid:service_id>/inbox.json")
@user_has_permissions("view_activity")
@service_has_permission("inbound_sms")
def inbox_updates(service_id):
return jsonify(get_inbox_partials(service_id))
@main.route("/services/<uuid:service_id>/inbox.csv")
@user_has_permissions("view_activity")
def inbox_download(service_id):
return Response(
Spreadsheet.from_rows(
[
[
"Phone number",
"Message",
"Received",
]
]
+ [
[
format_phone_number_human_readable(message["user_number"]),
message["content"].lstrip(("=+-@")),
format_datetime_numeric(message["created_at"]),
]
for message in service_api_client.get_inbound_sms(service_id)["data"]
]
).as_csv_data,
mimetype="text/csv",
headers={
"Content-Disposition": 'inline; filename="Received text messages {}.csv"'.format(
format_date_numeric(datetime.utcnow().isoformat())
)
},
)
def get_inbox_partials(service_id):
page = int(request.args.get("page", 1))
inbound_messages_data = service_api_client.get_most_recent_inbound_sms(
service_id, page=page
)
inbound_messages = inbound_messages_data["data"]
if not inbound_messages:
inbound_number = current_service.inbound_number
else:
inbound_number = None
prev_page = None
if page > 1:
prev_page = generate_previous_dict("main.inbox", service_id, page)
next_page = None
if inbound_messages_data["has_next"]:
next_page = generate_next_dict("main.inbox", service_id, page)
return {
"messages": render_template(
"views/dashboard/_inbox_messages.html",
messages=inbound_messages,
inbound_number=inbound_number,
prev_page=prev_page,
next_page=next_page,
)
}
def filter_out_cancelled_stats(template_statistics):
return [s for s in template_statistics if s["status"] != "cancelled"]
@@ -325,71 +262,6 @@ def aggregate_template_usage(template_statistics, sort_key="count"):
return sorted(templates, key=lambda x: x[sort_key], reverse=True)
def aggregate_notifications_stats(template_statistics):
template_statistics = filter_out_cancelled_stats(template_statistics)
notifications = {
template_type: {status: 0 for status in ("requested", "delivered", "failed")}
for template_type in ["sms", "email"]
}
for stat in template_statistics:
notifications[stat["template_type"]]["requested"] += stat["count"]
if stat["status"] in DELIVERED_STATUSES:
notifications[stat["template_type"]]["delivered"] += stat["count"]
elif stat["status"] in FAILURE_STATUSES:
notifications[stat["template_type"]]["failed"] += stat["count"]
return notifications
def get_dashboard_partials(service_id):
all_statistics = template_statistics_client.get_template_statistics_for_service(
service_id, limit_days=7
)
template_statistics = aggregate_template_usage(all_statistics)
stats = aggregate_notifications_stats(all_statistics)
dashboard_totals = (get_dashboard_totals(stats),)
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(
current_service.id,
)
# These 2 calls will update the dashboard sms allowance count while in trial mode.
billing_api_client.get_monthly_usage_for_service(
service_id, get_current_financial_year()
)
billing_api_client.create_or_update_free_sms_fragment_limit(
service_id, free_sms_fragment_limit=free_sms_allowance
)
yearly_usage = billing_api_client.get_annual_usage_for_service(
service_id,
get_current_financial_year(),
)
return {
"upcoming": render_template(
"views/dashboard/_upcoming.html",
),
"inbox": render_template(
"views/dashboard/_inbox.html",
),
"totals": render_template(
"views/dashboard/_totals.html",
service_id=service_id,
statistics=dashboard_totals[0],
),
"template-statistics": render_template(
"views/dashboard/template-statistics.html",
template_statistics=template_statistics,
most_used_template_count=max(
[row["count"] for row in template_statistics] or [0]
),
),
"usage": render_template(
"views/dashboard/_usage.html",
**get_annual_usage_breakdown(yearly_usage, free_sms_allowance),
),
}
def get_dashboard_totals(statistics):
for msg_type in statistics.values():

View File

@@ -23,10 +23,11 @@ from app.utils.user import user_is_logged_in
# Hook to check for feature flags
@main.before_request
def check_feature_flags():
if request.path.startswith("/about") and not current_app.config.get(
"FEATURE_ABOUT_PAGE_ENABLED", False
):
abort(404)
# Placeholder for future feature flag checks
# Example:
# if request.path.startswith("/some-feature") and not current_app.config.get("FEATURE_SOME_FEATURE_ENABLED", False):
# abort(404)
pass
@main.route("/test/feature-flags")
@@ -258,11 +259,11 @@ def why_text_messaging():
)
@main.route("/join-notify")
def join_notify():
@main.route("/notify-service-ending")
@user_is_logged_in
def notify_service_ending():
return render_template(
"views/join-notify.html",
navigation_links=about_notify_nav(),
"views/notify-service-ending.html",
)

View File

@@ -116,6 +116,70 @@ def download_all_users():
return response
@main.route("/platform-admin/get-redis-report")
@user_is_platform_admin
def get_redis_report():
memory_info = redis_client.info("memory")
memory_used = memory_info.get("used_memory_human", "N/A")
max_memory = memory_info.get("maxmemory_human", "N/A")
if max_memory == "0B":
max_memory = "No set limit"
mem_fragmentation = memory_info.get("mem_fragmentation_ratio", "N/A")
frag_quality = "Swapping (bad)"
if mem_fragmentation >= 1.0:
frag_quality = "Healthy"
if mem_fragmentation > 1.5:
frag_quality = "Problematic"
if mem_fragmentation > 2.0:
frag_quality = "Severe fragmentation"
frag_note = ""
if mem_fragmentation > 2.0:
frag_note = "Use MEMORY PURGE.\nReplace multiple small keys with hashes.\nAvoid long keys.\nSet max_memory."
elif mem_fragmentation < 1.0:
frag_note = "Allocate more RAM.\nSet max_memory."
keys = redis_client.keys("*")
key_details = []
for key in keys:
key_type = redis_client.type(key).decode("utf-8")
ttl = redis_client.ttl(key)
ttl_str = "No Expiry" if ttl == -1 else f"{ttl} seconds"
key_details.append(
{"Key": key.decode("utf-8"), "Type": key_type, "TTL": ttl_str}
)
output = StringIO()
writer = csv.writer(
output,
)
writer.writerow(["Redis Report"])
writer.writerow([])
writer.writerow(["Memory"])
writer.writerow(["", "Memory Used", memory_used])
writer.writerow(["", "Max Memory", max_memory])
writer.writerow(["", "Memory Fragmentation Ratio", mem_fragmentation])
writer.writerow(["", "Memory Fragmentation Quality", frag_quality, frag_note])
writer.writerow([])
writer.writerow(["Keys Overview"])
writer.writerow(["", "TTL", "Type", "Key"])
for key_detail in key_details:
writer.writerow(
["", key_detail["TTL"], key_detail["Type"], key_detail["Key"][0:50]]
)
csv_data = output.getvalue()
# Create a direct download response with the CSV data and appropriate headers
response = Response(csv_data, content_type="text/csv; charset=utf-8")
response.headers["Content-Disposition"] = "attachment; filename=redis.csv"
return response
def is_over_threshold(number, total, threshold):
percentage = number / total * 100 if total else 0
return percentage > threshold

View File

@@ -167,7 +167,7 @@ def send_messages(service_id, template_id):
# just show the first error, as we don't expect the form to have more
# than one, since it only has one field
first_field_errors = list(form.errors.values())[0]
error_message = '<span class="usa-error-message">'
error_message = '<span class="error-message usa-error-message">'
error_message = f"{error_message}{first_field_errors[0]}"
error_message = f"{error_message}</span>"
error_message = Markup(error_message)
@@ -924,6 +924,10 @@ def get_template_error_dict(exception):
def preview_notification(service_id, template_id):
recipient = get_recipient()
if not recipient:
current_app.logger.warning(
f"No recipient found for service {service_id}, template {template_id}. Redirecting..."
)
return redirect(
url_for(
".send_one_off",

View File

@@ -68,11 +68,12 @@ def _get_access_token(code): # pragma: no cover
id_token = get_id_token(response_json)
nonce = id_token["nonce"]
nonce_key = f"login-nonce-{unquote(nonce)}"
stored_nonce = redis_client.get(nonce_key).decode("utf8")
if not os.getenv("NOTIFY_ENVIRONMENT") == "development":
stored_nonce = redis_client.get(nonce_key).decode("utf8")
if nonce != stored_nonce:
current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}")
abort(403)
if nonce != stored_nonce:
current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}")
abort(403)
try:
access_token = response_json["access_token"]
@@ -112,7 +113,7 @@ def _do_login_dot_gov(): # $ pragma: no cover
verify_key = f"login-verify_email-{unquote(state)}"
verify_path = bool(redis_client.get(verify_key))
if not verify_path:
if not verify_path and not os.getenv("NOTIFY_ENVIRONMENT") == "development":
state_key = f"login-state-{unquote(state)}"
stored_state = unquote(redis_client.get(state_key).decode("utf8"))
if state != stored_state:

View File

@@ -56,10 +56,6 @@ def about_notify_nav():
},
],
},
{
"name": "Join Notify",
"link": "main.join_notify",
},
{
"name": "Contact us",
"link": "main.contact",

View File

@@ -680,41 +680,45 @@ def count_content_length(service_id, template_type):
)
def _is_latin1(s):
return bool(s.encode(encoding="latin-1", errors="strict"))
def _get_content_count_error_and_message_for_template(template):
url = "https://en.wikipedia.org/wiki/ISO/IEC_8859-1"
if template.template_type == "sms":
s1 = f"<html><body>Use of characters outside the <a href='{url}'>IEC_8859-1</a> character set may increase "
s2 = "the message fragment count, resulting in additional charges, and these IEC_8859-1 "
s3 = "characters may not display properly on some older mobile devices.</body></html>"
s1 = (
"<html><body>Looks like your template may have one of these characters "
"• ™ ∞ ≤ or ≥ or emoji, which won't save."
)
s2 = "<br>Please remove any unaccepted characters or emojis and try again.</body></html>"
warning = ""
try:
_is_latin1(template.content)
except UnicodeEncodeError:
warning = f"{s1}{s2}{s3}"
# Define characters that should be blocked
BLOCKED_CHARACTERS = {"", "", "", "", ""}
def contains_blocked_characters(content):
"""Check if the content contains explicitly blocked characters."""
return any(c in BLOCKED_CHARACTERS for c in content)
# Check for blocked characters
if contains_blocked_characters(template.content):
warning = f"{s1}{s2}"
return False, Markup(
warning
) # 🚨 ONLY show the warning, hiding "Will be charged..."
# If message is too long, return the length error
if template.is_message_too_long():
return True, (
f"You have "
f"{character_count(template.content_count_without_prefix - SMS_CHAR_COUNT_LIMIT)} "
f"too many"
)
# Show charge message as usual if no warning
if template.placeholders:
return False, (
Markup(
f"Will be charged as {message_count(template.fragment_count, template.template_type)} "
f"(not including personalization). {warning}"
)
)
return False, (
# Markup marks html contents safe so that they render properly. Don't use it if there is user input.
Markup(
f"Will be charged as {message_count(template.fragment_count, template.template_type)}. {warning} "
return False, Markup(
f"Will be charged as {message_count(template.fragment_count, template.template_type)} "
f"(not including personalization)."
)
return False, Markup(
f"Will be charged as {message_count(template.fragment_count, template.template_type)}."
)

View File

@@ -58,8 +58,6 @@ class HeaderNavigation(Navigation):
},
"accounts-or-dashboard": {
"conversation",
"inbox",
"monthly",
"service_dashboard",
"template_usage",
"view_notification",
@@ -161,8 +159,6 @@ class MainNavigation(Navigation):
},
"dashboard": {
"conversation",
"inbox",
"monthly",
"service_dashboard",
"template_usage",
"view_notification",

View File

@@ -537,6 +537,11 @@ class ServiceAPIClient(NotifyAdminAPIClient):
"""
return self.get("/service/invite/redis/{0}".format(redis_key))
def get_service_message_ratio(self, service_id):
return self.get(
url="service/get-service-message-ratio?service_id={0}".format(service_id),
)
service_api_client = ServiceAPIClient()

View File

@@ -116,7 +116,7 @@ class UserApiClient(NotifyAdminAPIClient):
data["next"] = next_string
if code_type == "email":
data["email_auth_link_host"] = self.admin_url
endpoint = f"/user/{user_id}/{code_type}-code"
endpoint = f"/user/{user_id}/{code_type}-code"
current_app.logger.warn(hilite(f"Sending verify_code {code_type} to {user_id}"))
self.post(endpoint, data=data)

View File

@@ -14,10 +14,8 @@
<script nonce="{{ csp_nonce() }}">document.body.className = ((document.body.className) ? document.body.className + ' js-enabled' : 'js-enabled');</script>
{% block bodyStart %}
{% block extra_javascripts_before_body %}
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-WX5NGWF"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
{% endblock %}
{% endblock %}
@@ -31,6 +29,30 @@
{% block header %}
{% include 'components/usa_banner.html' %}
{% if current_user.is_authenticated or current_service or current_user.platform_admin %}
<section class="usa-site-alert usa-site-alert--info" aria-label="Site alert,,,,">
<div class="usa-alert">
<div class="usa-alert__body">
<p class="usa-alert__heading text-bold">Notify.gov Service Ending</p>
<p class="usa-alert__text">
GSA will no longer offer the Notify.gov service after June 8th, 2025. Visit
<a class="usa-link" href="/notify-service-ending">Notify.gov Service Ending</a> for more information.
</p>
</div>
</div>
</section>
{% else %}
<section class="usa-site-alert usa-site-alert--emergency usa-site-alert--no-heading" aria-label="Site alert,,,,">
<div class="usa-alert">
<div class="usa-alert__body">
<p class="usa-alert__heading text-bold">Notify.gov Service Ending</p>
<p class="usa-alert__text">
Notify.gov is no longer accepting new partners.
</p>
</div>
</div>
</section>
{% endif %}
{% include 'components/header.html' %}
{% endblock %}
@@ -96,10 +118,10 @@
{% block footer %}
{% if current_service and current_service.research_mode %}
{% set meta_suffix = 'Built by the <a href="https://www.gsa.gov/about-us/organization/federal-acquisition-service/technology-transformation-services/tts-solutions" class="usa-link">Technology Transformation Services</a><span id="research-mode" class="research-mode">research mode</span>' %}
{% set meta_suffix = 'Built by the <a href="https://tts.gsa.gov/" class="usa-link">Technology Transformation Services</a><span id="research-mode" class="research-mode">research mode</span>' %}
{% else %}
{% set commit_hash = ", Latest version: " + config['COMMIT_HASH'] %}
{% set long_link = '<a href="https://www.gsa.gov/about-us/organization/federal-acquisition-service/technology-transformation-services/tts-solutions" class="usa-link">Technology Transformation Services</a>' %}
{% set long_link = '<a href="https://tts.gsa.gov/" class="usa-link">Technology Transformation Services</a>' %}
{% set meta_suffix = "Built by the " + long_link + commit_hash %}
{% endif %}
@@ -145,10 +167,8 @@
{% block bodyEnd %}
{% block extra_javascripts %}
{% endblock %}
<!--[if gt IE 8]><!-->
<script type="text/javascript" src="{{ asset_url('javascripts/all.js') }}"></script>
<script type="text/javascript" src="{{ asset_url('js/uswds.min.js') }}"></script>
<!--<![endif]-->
{% endblock %}
</body>
</html>

View File

@@ -16,7 +16,7 @@
{#- Define common attributes we can use for both button and input types #}
{%- set buttonAttributes %}{% if params.name %} name="{{ params.name }}"{% endif %} type="{{ params.type if params.type else 'submit' }}"{% if params.disabled %} disabled="disabled" aria-disabled="true"{% endif %}{% if params.preventDoubleClick %} data-prevent-double-click="true"{% endif %}{% endset %}
{%- set buttonAttributes %}{% if params.name %} name="{{ params.name | trim }}"{% endif %} type="{{ params.type if params.type else 'submit' }}"{% if params.disabled %} disabled="disabled" aria-disabled="true"{% endif %}{% if params.preventDoubleClick %} data-prevent-double-click="true"{% endif %}{% endset %}
{#- Actually create a button... or a link! #}

View File

@@ -12,7 +12,7 @@
classes: params.label.classes,
isPageHeading: params.label.isPageHeading,
attributes: params.label.attributes,
for: params.id
for: params.text
}) | indent(2) | trim }}
{% if params.hint %}
{% set hintId = params.id + '-hint' %}
@@ -26,7 +26,7 @@
}) | indent(2) | trim }}
{% endif %}
{% if params.errorMessage %}
{% set errorId = params.id + '-error' %}
{% set errorId = params.label.text + '-error' %}
{% set describedBy = describedBy + ' ' + errorId if describedBy else errorId %}
{{ usaErrorMessage({
id: errorId,
@@ -37,12 +37,16 @@
visuallyHiddenText: params.errorMessage.visuallyHiddenText,
}) | indent(2) | trim }}
{% endif %}
<input class="usa-input {%- if params.classes %} {{ params.classes }}{% endif %} {%- if params.errorMessage %} usa-input--error{% endif %}" id="{{ params.id }}" name="{{ params.name }}" type="{{ params.type | default('text') }}"
{%- if params.value %} value="{{ params.value}}"{% endif %}
{%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %}
{%- if params.autocomplete %} autocomplete="{{ params.autocomplete}}"{% endif %}
{%- if params.pattern %} pattern="{{ params.pattern }}"{% endif %}
{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}
{%- if params.required %} required{% endif %}
<input
class="usa-input {%- if params.classes %} {{ params.classes }}{% endif %} {%- if params.errorMessage %} usa-input--error{% endif %}"
id="{{ params.label.text | default('unknown') | slugify }}"
name="{{ params.name }}"
type="{{ params.type | default('text') }}"
{%- if params.value %} value="{{ params.value }}"{% endif %}
{%- if describedBy %} aria-describedby="{{ describedBy }}"{% endif %}
{%- if params.autocomplete %} autocomplete="{{ params.autocomplete }}"{% endif %}
{%- if params.pattern %} pattern="{{ params.pattern }}"{% endif %}
{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor -%}
{%- if params.required %} required{% endif %}
/>
</div>

View File

@@ -20,7 +20,7 @@
</span>
{% endif %}
{% if field.errors and show_errors %}
<span class="error-message">
<span class="error-message usa-error-message">
{{ field.errors[0] }}
</span>
{% endif %}

View File

@@ -5,7 +5,8 @@
class=None,
id=None,
module=None,
data_kwargs={}
data_kwargs={},
data_force_focus=False
) %}
<form
method="{{ method }}"
@@ -19,6 +20,7 @@
data-{{ key }}="{{ val }}"
{% endif %}
{% endfor %}
{% if data_force_focus %}data-force-focus="{{ data_force_focus }}"{% endif %}
novalidate
>
{{ caller() }}

View File

@@ -1,7 +1,6 @@
{% set is_about_page = request.path.startswith('/about') %}
{% set is_join_notify_page = request.path.startswith('/join-notify') %}
{% set is_contact_page = request.path.startswith('/contact') %}
{% set is_information_section = is_about_page or is_join_notify_page or is_contact_page %}
{% set is_information_section = is_about_page or is_contact_page %}
{% if current_user.is_authenticated %}
{% set navigation = [
@@ -34,11 +33,16 @@
{% else %}
{% set navigation = [
{"href": url_for('main.about_notify'), "text": "About Notify", "active": is_about_page},
{"href": url_for('main.join_notify'), "text": "Join Notify", "active": is_join_notify_page},
{"href": url_for('main.contact'), "text": "Contact us", "active": is_contact_page}
] %}
{% endif %}
<header class="usa-header usa-header--extended">
<div class="usa-nav-container">
<div class="usa-navbar">
@@ -47,7 +51,7 @@
<div class="logo-img display-flex">
<a href="/">
<span class="usa-sr-only">Notify.gov logo</span>
<img src="{{ (asset_path | default('/static')) + 'images/notify-logo.svg' }}" alt=""
<img src="{{ (asset_path | default('/static')) + 'images/notify-logo.svg' }}" alt="Notify.gov logo"
class="usa-flag-logo margin-right-1">
</a>
</div>
@@ -55,6 +59,14 @@
<button type="button" class="usa-menu-btn">Menu</button>
{% endif %}
</div>
{% if not current_user.is_authenticated and is_information_section%}
<div class="usa-nav__login">
<a class="usa-button usa-button login-button login-button--primary margin-right-2"
href="{{ initial_signin_url }}">Sign
in with <img src="{{ asset_url('images/logo-login.svg') }}" alt="Login.gov logo">
</a>
</div>
{% endif %}
</div>
</div>
@@ -75,11 +87,7 @@
{% endif %}
{% endfor %}
</ul>
{% if not current_user.is_authenticated %}
<div class="usa-nav__secondary margin-bottom-2">
{% else %}
<div class="usa-nav__secondary margin-bottom-6">
{% endif %}
<ul class="usa-nav__secondary-links">
{% if secondaryNavigation %}
{% for item in secondaryNavigation %}
@@ -94,19 +102,8 @@
{% endfor %}
{% endif %}
</ul>
{% if not current_user.is_authenticated %}
<div class="usa-nav__login display-flex flex-align-center">
<span class="margin-right-2 display-none desktop:display-block">
If you are an existing partner
</span>
<a id="header_login_button" class="usa-button login-button login-button--primary desktop:padding-2 padding-1"
href="{{ initial_signin_url }}">
Sign in with
<img src="{{ asset_url('images/logo-login.svg') }}" alt="Login.gov logo">
</a>
</div>
{% endif %}
</div>
</div>
</nav>
</div>

View File

@@ -32,7 +32,7 @@
<legend class="form-label {% if bold_legend %}bold{% endif %}">
{{ field.label.text }}
{% if field.errors %}
<span class="error-message" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}">
<span class="error-message usa-error-message" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}">
{{ field.errors[0] }}
</span>
{% endif %}

View File

@@ -52,7 +52,7 @@
</span>
{% endif %}
{% if field.errors %}
<span class="error-message" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}">
<span class="error-message usa-error-message" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}">
{{ field.errors[0] }}
</span>
{% endif %}

View File

@@ -32,7 +32,7 @@
</div>
{% 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 }}" tabindex="-1" aria-live="assertive" role="alert">
<span id="{{ field.name}}-error" class="error-message usa-error-message" data-module="track-error" data-error-type="{{ field.errors[0] }}" data-error-label="{{ field.name }}" tabindex="-1" aria-live="assertive" role="alert">
<span class="usa-sr-only">Error:</span>
{% if not safe_error_message %}{{ field.errors[0] }}{% else %}{{ field.errors[0]|safe }}{% endif %}
</span>

View File

@@ -25,7 +25,7 @@
{% if job.scheduled_for %}
<div class="usa-alert usa-alert--info">
<div class="usa-alert__body">
<h2 class="usa-alert__heading">Your message has been scheduled</h2>
<h2 class="usa-alert__heading">Your {{ 'message has' if job.notification_count == 1 else 'messages have' }} been scheduled</h2>
<p class="usa-alert__text">
{{ job.template_name }} - {{ current_service.name }} was scheduled on {{ job.scheduled_for|format_datetime_normal }} by {{ job.created_by.name }}
</p>
@@ -37,7 +37,7 @@
<div class="usa-alert usa-alert--success">
<div class="usa-alert__body">
<h2 class="usa-alert__heading">
Your message is sending
Your {{ 'message is' if job.notification_count == 1 else 'messages are' }} sending
</h2>
<p class="usa-alert__text">
{{ job.template_name }} - {{ current_service.name }}
@@ -49,7 +49,7 @@
<div class="usa-alert usa-alert--info">
<div class="usa-alert__body">
<h2 class="usa-alert__heading">
Your message is pending
Your {{ 'message is' if job.notification_count == 1 else 'messages are' }} pending
</h2>
<p class="usa-alert__text">
{{ job.template_name }} - {{ current_service.name }}
@@ -64,7 +64,7 @@
<div class="usa-alert usa-alert--success">
<div class="usa-alert__body">
<h2 class="usa-alert__heading">
Your message has been sent
Your {{ 'message has' if job.notification_count == 1 else 'messages have' }} been sent
</h2>
<p class="usa-alert__text">
{{ job.template_name }} - {{ current_service.name }}

View File

@@ -5,10 +5,6 @@
</h3>
<div id="message-length" class="usa-accordion__content usa-prose">
<p class="usa-body">
If your message is long then it will
cost more.
</p>
<p class="usa-body">
See <a class="usa-link" href="{{ url_for('.pricing') }}">pricing</a> for details.
Each message sent to a recipient counts as one text. Keep track on your Dashboard of how many messages have sent and are remaining.
</p>
</div>

View File

@@ -7,7 +7,7 @@
</h3>
<div id="m-a2" class="usa-accordion__content usa-prose">
<p class="usa-body">
Use double brackets and ?? to define optional content.
Use double parenthesis and ?? to define optional content.
</p>
<p class="bottom-gutter-1-3">
For example if you only want to show something to people who are under

View File

@@ -7,11 +7,10 @@
</h3>
<div id="personalization" class="usa-accordion__content usa-prose">
<p class="bottom-gutter-1-3">
Use double brackets to personalize your message:
Use double parenthesis to personalize your message:
</p>
{{ usaInsetText({
"text": "Hello ((first name)), your reference is ((ref number))",
"classes": ""})
}}
</div>

View File

@@ -4,7 +4,7 @@
Send a document by email
</h2>
<p class="usa-body">
Use double brackets to add a placeholder field to your template. This will contain a secure link to download the document.
Use double parenthesis to add a placeholder field to your template. This will contain a secure link to download the document.
</p>
{{ usaInsetText({
"text": "Download your document at: ((link_to_file))",

View File

@@ -66,7 +66,6 @@
</li>
{% endfor %}
</ul>
<p><a href="/join-notify">See if Notify is right for you</a></p>
<p>Notify.gov is a product of the <a href="/studio">Public Benefits Studio</a>, a product accelerator inside
the federal government. </p>
</section>

View File

@@ -40,8 +40,7 @@
</p>
<p>
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 <a href="/join-notify">you can get started for free</a>, allowing you to try out
texting to complement your existing communications and outreach strategies.
way to do so.
</p>
<h2 id="what-texting-is-best-for">What texting is best for</h2>
<p>

View File

@@ -14,7 +14,7 @@
{{ page_header('About your service') }}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ form.name(param_extensions={"hint": {"text": "You can change this later"}}) }}

View File

@@ -102,7 +102,7 @@ Error
<div class="usa-alert usa-alert--error" role="alert">
<div class="usa-alert__body">
<h1 class="usa-alert__heading banner-title" data-module="track-error" data-error-type="Missing placeholder columns"
data-error-label="{{ upload_id }}">Your column names need to match the double brackets in your template</h1>
data-error-label="{{ upload_id }}">Your column names need to match the double parenthesis in your template</h1>
<p class="usa-alert__text">
Your file is missing {{ recipients.missing_column_headers | formatted_list(
conjunction='and',

View File

@@ -101,6 +101,9 @@
{% set button_text %}
{{ "Schedule" if scheduled_for else 'Send'}}
{% endset %}
{{ usaButton({ "text": button_text }) }}
{{ usaButton({
"text": button_text,
"name": button_text
}) }}
</form>
{% endblock %}

View File

@@ -7,19 +7,10 @@
{% block content_column_content %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p>Is your organization interested in using Notify.gov? Find more information at <a href="/join-notify">Join
Notify</a> or contact us at <a href="mailto:tts-notify@gsa.gov"
<p>For any questions, contact us at <a href="mailto:tts-notify@gsa.gov"
aria-label="contact us at tts-notify@gsa.gov">tts-notify@gsa.gov</a>.</p>
<p>You can expect a response within one business day.</p>
<div class="usa-summary-box maxw-tablet __web-inspector-hide-shortcut__" role="region"
aria-label="For partnership inquiries">
<div class="usa-summary-box__body">
<div class="usa-summary-box__text">
<p class="margin-0">If you are a current Notify.gov partner and have technical issues or questions, we are available at <a
href="mailto:notify-support@gsa.gov"
aria-label="Email Notify for technical questions at notify-support@gsa.gov">notify-support@gsa.gov</a></p>
</div>
</div>
</div>
<p>If you are a current Notify.gov partner and have technical issues or questions, we are available
at <a href="mailto:notify-support@gsa.gov"
aria-label="Email Notify for technical questions at notify-support@gsa.gov">notify-support@gsa.gov</a></p>
</section>
{% endblock %}

View File

@@ -8,7 +8,7 @@
{% endblock %}
{% block backLink %}
{{ usaBackLink({ "href": url_for("main.inbox", service_id=current_service.id) }) }}
{{ usaBackLink({ "href": url_for("main.service_dashboard", service_id=current_service.id) }) }}
{% endblock %}
{% block maincolumn_content %}

View File

@@ -1,17 +0,0 @@
<div class="ajax-block">
{% if current_service.inbound_sms_summary != None %}
<a id="total-received" class="usa-link banner-dashboard" class="banner-dashboard" href="{{ url_for('.inbox', service_id=current_service.id) }}">
<span class="banner-dashboard-count">
{{ current_service.inbound_sms_summary.count|format_thousands }}
</span>
<span class="banner-dashboard-count-label">
{{ current_service.inbound_sms_summary.count|message_count_label('sms', suffix='received') }}
</span>
{% if current_service.inbound_sms_summary.most_recent %}
<span class="banner-dashboard-meta">
latest message {{ current_service.inbound_sms_summary.most_recent | format_delta }}
</span>
{% endif %}
</a>
{% endif %}
</div>

View File

@@ -1,38 +0,0 @@
{% from "components/table.html" import list_table, field, hidden_field_heading, right_aligned_field_heading, row_heading %}
{% from "components/previous-next-navigation.html" import previous_next_navigation %}
<div class="ajax-block-container">
{% if messages %}
<p class="bottom-gutter-2-3 top-gutter-1-2">
<a href="{{ url_for('.inbox_download', service_id=current_service.id) }}" download class="usa-link bold">Download these messages</a>
</p>
{% endif %}
{% call(item, row_number) list_table(
messages,
caption="Inbox",
caption_visible=False,
empty_message='When users text your services phone number ({}) youll see the messages here'.format(inbound_number),
field_headings=[
'From',
'First two lines of message'
],
field_headings_visible=False
) %}
{% call field() %}
<a
class="usa-link file-list-filename"
href="{{ url_for('.conversation', service_id=current_service.id, notification_id=item.id) }}#n{{ item.id }}"
>
{{ item.user_number | format_phone_number_human_readable }}
</a>
<span class="file-list-hint">{{ item.content }}</span>
{% endcall %}
{% call field(align='right') %}
<span class="align-with-message-body">
{{ item.created_at | format_delta }}
</span>
{% endcall %}
{% endcall %}
{{ previous_next_navigation(prev_page, next_page) }}
</div>

View File

@@ -1,25 +0,0 @@
<div class="ajax-block-container">
<div class="grid-row grid-gap">
<div id="total-sms" class="grid-col-12 margin-top-2">
<span class="big-number-with-status display-block margin-bottom-2">
<p>
<span class="big-number-smaller">
<span class="big-number-number">
{% if statistics['sms']['requested'] is number %}
{{ "{:,}".format(statistics['sms']['requested']) }}
{% else %}
{{ statistics['sms']['requested'] }}
{% endif %}
</span>
<span class="big-number-label">{{ statistics['sms']['requested']|message_count_label('sms', suffix='sent') }} in the last seven days</span>
</span>
</p>
<a class="usa-button usa-button--outline" href="{{ url_for('.view_notifications', service_id=service_id, message_type='sms', status='sending,delivered,failed') }}">
Details
</a>
{# Removing the failures area for now, as the user can click on the above link to see all the details.
In the future state of the dashboard, the all statuses will be more apparent with data visualizations #}
</span>
</div>
</div>
</div>

View File

@@ -46,14 +46,16 @@
</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 }}
{% if not job.finished_processing %}
{% if job.scheduled_for%}
Scheduled for {{ job.scheduled_for|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 %}
{% else %}
Pending since {{ job.created_at|format_datetime_table }}
Sent on {{ job.processing_started|format_datetime_table }}
{% endif %}
</td>
<td class="table-field sender sender-column">{{ job.created_by.name }}</td>

View File

@@ -1,12 +1,12 @@
{% extends "withnav_template.html" %}
{% from "components/table.html" import list_table, field, text_field, link_field, right_aligned_field_heading, hidden_field_heading, row_heading, notification_status_field, notification_carrier_field, notification_carrier_message_field %}
{% from "components/table.html" import list_table, field, text_field, link_field, right_aligned_field_heading,
hidden_field_heading, row_heading, notification_status_field, notification_carrier_field,
notification_carrier_message_field %}
{% from "components/ajax-block.html" import ajax_block %}
{% block service_page_title %}
Dashboard
Dashboard
{% endblock %}
{% block maincolumn_content %}
@@ -15,29 +15,38 @@
<div class="dashboard margin-top-0 margin-bottom-2">
<h1 class="usa-sr-only">Dashboard</h1>
{% if current_user.has_permissions('manage_templates') and not current_service.all_templates %}
<h1 class="usa-sr-only">Dashboard</h1>
{% if current_user.has_permissions('manage_templates') and not current_service.all_templates %}
{% include 'views/dashboard/write-first-messages.html' %}
{% endif %}
{% endif %}
{{ ajax_block(partials, updates_url, 'upcoming') }}
{% include 'views/dashboard/_upcoming.html' %}
<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') }}
<div id="totalMessageChartContainer" data-messages-sent="{{ messages_sent }}" data-messages-remaining="{{ messages_remaining }}">
<div class="grid-row flex-align-center">
<h2 id="chartTitle" class="margin-right-1">Total messages</h2>
<button
type="button"
class="usa-tooltip usa-tooltip__information margin-right-0"
data-position="top"
title="Total messages track the sum of messages for the service: pending, failed, or delivered"
>
<span class="usa-sr-only">More information</span>
i
</button>
</div>
<svg id="totalMessageChart"></svg>
<div id="message"></div>
</div>
<div id="totalMessageTable" class="margin-0"></div>
{% include 'views/dashboard/activity-table.html' %}
<div id="totalMessageChartContainer" data-sms-sent="{{ sms_sent }}" data-sms-allowance-remaining="{{ sms_allowance_remaining }}">
<h2 id="chartTitle">Total messages</h2>
<svg id="totalMessageChart"></svg>
<div id="message"></div>
</div>
<div id="totalMessageTable" class="margin-0"></div>
{% if current_user.has_permissions('manage_service') %}{% endif %}
{% include 'views/dashboard/activity-table.html' %}
{% include 'views/dashboard/most-used-templates.html' %}
{% if current_user.has_permissions('manage_service') %}{% endif %}
{{ ajax_block(partials, updates_url, 'template-statistics') }}
</div>
{% endblock %}

View File

@@ -1,25 +0,0 @@
{% extends "withnav_template.html" %}
{% from "components/ajax-block.html" import ajax_block %}
{% from "components/page-header.html" import page_header %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% block service_page_title %}
Received text messages
{% endblock %}
{% block backLink %}
{{ usaBackLink({ "href": url_for('main.service_dashboard', service_id=current_service.id) }) }}
{% endblock %}
{% block maincolumn_content %}
{{ page_header('Received text messages') }}
{{ ajax_block(
partials,
updates_url,
'messages',
) }}
{% endblock %}

View File

@@ -34,12 +34,13 @@
<td><p>{{ item.template_folder }}</p></td>
<td><p>{{ item.last_used|format_datetime_table}}</p></td>
<td><p>{{ item.created_by }}</p></td>
<td><p>{{ item.count }}</p></td>
<td><p>{{ '{:,.0f}'.format(item.count) }}</p></td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="/services/78409625-0c0a-485e-b82c-b19c8f4b1bdb/template-usage" class="usa-link show-more-no-border"><span>See templates by month</span></a>
<a
href="{{ url_for('.template_usage', service_id=current_service.id) }}" class="usa-link show-more-no-border"><span>See templates by month</span></a>
</div>
{% endif %}
</div>

View File

@@ -27,8 +27,8 @@
{% set content_hint = 'Your service name will be added to the start of your message. You can turn this off in Settings.' %}
{% endif %}
{% call form_wrapper() %}
<div class="grid-row">
{% call form_wrapper(data_force_focus=True) %}
<div class="grid-container padding-0">
<div class="tablet:grid-col-9 mobile-lg:grid-col-12">
{{ form.name(param_extensions={
"extra_form_group_classes": "margin-bottom-2",
@@ -61,12 +61,12 @@
</div>
</div>
</div>
<div class="grid-row width-full">
<div class="grid-row width-mobile-lg">
<div class="tablet:grid-col-2 mobile-lg:grid-col-12">
{{ page_footer('Save') }}
</div>
<div class="tablet:grid-col-10 mobile-lg:grid-col-12">
<p class="usa-hint margin-top-5 tablet:margin-left-neg-2">
<p class="usa-hint margin-top-5 tablet:margin-left-2">
After saving, you'll have the option to send.
</p>
</div>

View File

@@ -61,7 +61,7 @@
<ol class="list list-number">
<li>Go to the {{ service_link(current_service, 'main.choose_template', 'templates') }} page.</li>
<li>Add a new template or choose an existing template and select <b class="bold">Edit</b>.</li>
<li>Add a placeholder using double brackets. For example: Hello ((first&nbsp;name)), your reference is ((ref&nbsp;number)).</li>
<li>Add a placeholder using double parenthesis. For example: Hello ((first&nbsp;name)), your reference is ((ref&nbsp;number)).</li>
<li>Select <b class="bold">Save</b>.</li>
</ol>
@@ -81,7 +81,7 @@
<ol class="list list-number">
<li>Go to the {{ service_link(current_service, 'main.choose_template', 'templates') }} page.</li>
<li>Add a new template or choose an existing template and select <b class="bold">Edit</b>.</li>
<li>Use double brackets and ?? to define optional content. For example, if you only want to show something to people who are under 18: ((under18??Please get your application signed by a parent or guardian.))</li>
<li>Use double parenthesis and ?? to define optional content. For example, if you only want to show something to people who are under 18: ((under18??Please get your application signed by a parent or guardian.))</li>
<li>Select <b class="bold">Save</b>.</li>
</ol>

View File

@@ -59,7 +59,7 @@ your recipient to manage their benefits and increase follow-through.</p>
<h3>To personalize your content</h3>
<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 parenthesis 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
work for you.</li>
</ol>
@@ -78,7 +78,7 @@ all or part of the message contingent upon specific criteria associated with the
<h3>To add conditional content</h3>
<ol class="list">
<li>Use two brackets and ?? to define the conditional content.</li>
<li>Use two parenthesis 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
do the work for you.</li>
</ol>

View File

@@ -11,7 +11,7 @@
{% block maincolumn_content %}
{{ page_header("Message status") }}
{% if not job.processing_finished %}
{% if not job.finished_processing %}
<div
data-module="update-content"
data-resource="{{ updates_url }}"
@@ -20,7 +20,7 @@
>
{% endif %}
{{ partials['status']|safe }}
{% if not job.processing_finished %}
{% if not job.finished_processing %}
</div>
{% endif %}
{% if not finished %}

View File

@@ -34,7 +34,7 @@
{% set product_highlights = [
{
"svg_src": "#chat",
"card_heading": "Up to 100,000 messages to use over your first year*",
"card_heading": "Up to 250,000 messages to use over your first year*",
},
{
"svg_src": "#phone",

View File

@@ -43,7 +43,6 @@
{% endcall %}
</div>
{% elif error == 'message-too-long' %}
{# the only row_errors we can get when sending one off messages is that the message is too long #}
<div class="bottom-gutter">
{% call banner_wrapper(type='dangerous') %}
{% include "partials/check/message-too-long.html" %}
@@ -77,13 +76,15 @@
help='3' if help else 0
)}}" class='page-footer'>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<!-- <p>Placeholder: This message will be delivered to <b>400 phone numbers</b> and will use a total of <b>800 message parts</b>, leaving Washington DSHS with <b>249,200 message parts remaining</b>.</p> -->
<h3>Does everything look good?</h3>
{% if not error %}
{% set button_text %}
{{ "Schedule" if scheduled_for else 'Send'}}
{% endset %}
{{ usaButton({ "text": button_text }) }}
{{ usaButton({
"text": button_text,
"name": button_text
}) }}
{% endif %}
</form>
</div>

View File

@@ -0,0 +1,28 @@
{% extends "base.html" %}
{% set page_title = "Notify.gov Service Ending" %}
{% block per_page_title %}{{page_title}}{% endblock %}
{% block content_column_content %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p>GSA will no longer offer the Notify.gov service after June 8th, 2025. Current partners will continue to have service access until it is fully suspended. After May 30, partners will no longer be able to send messages, and the full service will be suspended by June 8, 2025.
</p>
<h2>Notify.gov Status Announcement</h2>
<p class="text-italic">Notify.gov was in beta and will no longer be offered by GSA. Operations will be suspended on or before June 8. There is a chance that the service may need to stop sooner. GSA will keep partners informed to the extent possible.</p>
<p class="text-italic">All Notify.gov partners will be moved to trial mode no later than May 30, and will no longer be able to send messages. Partners will be able to access their templates and data through June 8.</p>
<p class="text-italic">We encourage government programs to explore ways to continue utilizing technology to meet people where they are. There are several commercial tools on the market that may work for Notify.gov use cases.</p>
<p class="text-italic">GSA is working to avoid potential disruptions to partners operations and ensure a smooth transition.</p>
<p class="text-italic">This decision is part of GSAs renewed focus on its original mission: to be the backbone of the federal governments administrative operations — streamlining processes, optimizing resources, and ensuring cost-effectiveness. GSA is driven to reducing federal spend, contributing to a more flexible and streamlined government, and delivering value for the American people.</p>
<p class="text-italic">We wish you all the best as you continue your work. </p>
</section>
{% endblock %}

View File

@@ -34,5 +34,8 @@
<p>
<a class="usa-link" href="{{ url_for('main.download_all_users') }}">Download All Users</a>
</p>
<p>
<a class="usa-link" href="{{ url_for('main.get_redis_report') }}">Get Redis Report</a>
</p>
{% endblock %}

View File

@@ -34,9 +34,12 @@
{% call form_wrapper(
class='js-stick-at-top-when-scrolling send-one-off-form' if template.template_type != 'sms' else 'send-one-off-form',
module="autofocus",
data_kwargs={'force-focus': True}
data_kwargs={'force-focus': True},
data_force_focus=True
) %}
<div class="grid-row">
{% set extra_class = "extra-tracking" if form.placeholder_value.label.text == "phone number" else "" %}
{% set placeholder_id = "phone number" if form.placeholder_value.label.text == "phone number" else "" %}
<div class="grid-col-12 {% if form.placeholder_value.label.text == 'phone number' %}extra-tracking{% endif %}">
{{ form.placeholder_value(param_extensions={"classes": "", "id": "phone-number"}) }}
</div>

View File

@@ -29,13 +29,6 @@
</div>
<h2 class="font-body-lg">Your file needs to look like this example</h2>
<p class="hint">
Save your file as a
<abbr title="Comma Separated Values">CSV</abbr><span aria-hidden="true">, </span>
<abbr title="Tab Separated Values">TSV</abbr><span aria-hidden="true">, </span>
<abbr title="Open Document Spreadsheet">ODS</abbr>
or Microsoft Excel spreadsheet.
</p>
<div class="spreadsheet" data-module="fullscreen-table">
{% call(item, row_number) list_table(
@@ -50,10 +43,14 @@
{% endfor %}
{% endcall %}
</div>
<p class="table-show-more-link">
<a class="usa-link" href="{{ url_for('.get_example_csv', service_id=current_service.id, template_id=template.id) }}" download>Download this example (<abbr title="Comma separated values">CSV</abbr>)</a>
<p class="hint">
Save your spreadsheet as a <abbr title="Comma Separated Values">CSV</abbr> file for bulk messaging. It is the most reliable when uploading your contact list. Start by downloading this example for your message template.
</p>
<p class="table-show-more-link">
<a class="usa-link display-flex margin-top-1" href="{{ url_for('.get_example_csv', service_id=current_service.id, template_id=template.id) }}" download>Download this example (<abbr title="Comma separated values">CSV</abbr>)
<img class="margin-left-05" src="{{ asset_url('img/material-icons/download.svg') }}" alt="" />
</a>
</p>
<h2 class="font-body-lg margin-bottom-1">Your file will populate this template:<br><span class="font-body-lg">({{ template.name }})</span></h2>
{{ template|string }}

View File

@@ -24,7 +24,7 @@
label='Search by name',
autofocus=True
) }}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{% if has_organizations %}
{{ form.organizations }}
{{ sticky_page_footer('Save') }}

View File

@@ -14,7 +14,7 @@
{% block maincolumn_content %}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ page_header('Free text message allowance') }}
{{ form.free_sms_allowance }}
{{ page_footer('Save') }}

View File

@@ -24,7 +24,7 @@
See <a class="usa-link" href="{{ url_for(".pricing") }}">pricing</a> for the list
of rates.
</p>
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ form.enabled }}
{{ page_footer('Save') }}
{% endcall %}

View File

@@ -14,7 +14,7 @@
{% block maincolumn_content %}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ page_header('Message batch limit') }}
{{ form.message_limit }}
{{ page_footer('Save') }}

View File

@@ -14,7 +14,7 @@
{% block maincolumn_content %}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ page_header('Rate limit') }}
{{ form.rate_limit }}
{{ page_footer('Save') }}

View File

@@ -15,7 +15,7 @@
<div class="grid-row">
<div class="grid-col-10">
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ form.enabled(param_extensions={
"fieldset": {
"legend": {

View File

@@ -20,12 +20,7 @@
<p>
You may send up to 250,000 text messages during the pilot period.
</p>
<!--<p>
You have a free allowance of
{{ '{:,}'.format(current_service.free_sms_fragment_limit) }} text messages each
financial year.
</p>-->
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ form.enabled }}
{{ page_footer('Save') }}
{% endcall %}

View File

@@ -16,7 +16,7 @@
{{ page_header('Start text messages with service name') }}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ form.enabled }}
{{ page_footer('Save') }}
{% endcall %}

View File

@@ -16,7 +16,7 @@
{{ page_header('Add text message sender') }}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{{ form.sms_sender(param_extensions={
"hint": {"text": "Up to 11 characters, letters, numbers and spaces only"}
}) }}

View File

@@ -18,7 +18,7 @@
{% block maincolumn_content %}
{{ page_header('Change text message sender') }}
{% call form_wrapper() %}
{% call form_wrapper(data_force_focus=True) %}
{% if inbound_number %}
<p>
<span class="bottom-gutter-1-3"> {{ sms_sender.sms_sender }} </span>

View File

@@ -9,65 +9,70 @@ import usaButton %} {% block meta %}
<main id="main-content" role="main">
{% block content %}
<section class="usa-section--dark usa-hero padding-y-2" aria-label="Introduction">
<section class="usa-section--dark usa-hero" aria-label="Introduction">
<div class="grid-container padding-y-4">
<div class="grid-row grid-gap display-flex flex-align-center">
<div class="desktop:grid-col-8 tablet:grid-col-12">
<h1 class="usa-hero__heading">
<h1 class="font-sans-2xl usa-hero__heading">
Reach people where they are with government-powered text messages
</h1>
<p class="desktop:font-sans-lg font-sans-md">
<p class="font-sans-lg">
Notify.gov is a text messaging service that helps federal, state,
local, tribal and territorial governments more effectively
communicate with the people they serve.
</p>
<div class="usa-button-group margin-bottom-5 flex-align-center">
<a
class="usa-button usa-button login-button login-button--primary margin-right-2"
href="{{ initial_signin_url }}"
>Sign in with
<img
src="{{ asset_url('images/logo-login.svg') }}"
alt="Login.gov logo"
/>
</a>
if you are an existing partner
</div>
</div>
<div
class="desktop:grid-col-4 desktop:display-block display-none"
class="desktop:grid-col-3 grid-offset-1 desktop:display-block display-none margin-x-5"
>
<img
src="{{ asset_url('images/product/hero-icons.svg') }}"
alt=""
src="{{ asset_url('images/product/phone-text.png') }}"
alt="Illustration of a mobile phone displaying a text message and number on its screen, with a speech bubble coming out from outside the phone, symbolizing communication or notification."
/>
</div>
</div>
</div>
</section>
<section class="grid-container usa-section usa-section__home border-top border-base-lighter usa-prose padding-bottom-4">
<div class="grid-row flex-align-center flex-justify-center">
<div class="tablet:grid-col-4 mobile-lg:grid-col-12 display-flex flex-justify-center margin-bottom-6">
<img
src="{{ asset_url('images/product/couple-looking-at-phone.png') }}"
alt="A couple smiling and looking at a cell phone together"/>
</div>
<div class="tablet:grid-col-6 tablet:margin-left-8 mobile-lg:grid-col-12">
<h2 class="font-body-xl margin-top-0 margin-bottom-3">
Government texting made easy
</h2>
<p class="usa-body margin-bottom-5">
Notify.gov is a text messaging platform built for government agencies.
With minimal set-up and secure, personalized messaging, you can make
one-way texting a part of your outreach program.
</p>
<a class="usa-button usa-button--big" href="/about">Learn more about Notify.gov</a>
</div>
</div>
<section
class="grid-container usa-section usa-section__home border-top border-base-lighter usa-prose padding-bottom-1"
>
<h2 class="font-body-xl margin-top-0 margin-bottom-3">
Government texting made easy
</h2>
<p class="usa-body">
Notify.gov is a text messaging platform built for government agencies.
With minimal set-up and secure, personalized messaging, you can make
one-way texting a part of your outreach program.
</p>
</section>
<section class="usa-section usa-section__home usa-prose key-features padding-bottom-4">
<h2 class="text-center margin-top-0">Key features</h2>
<div class="grid-container home-cards margin-top-5">
<section
class="grid-container usa-section usa-section__home usa-prose padding-bottom-1"
>
<h2 class="font-sans-xl margin-top-0">Key features</h2>
<div class="home-cards margin-top-5">
<ul class="usa-card-group display-flex margin-bottom-4">
<li class="usa-card tablet:grid-col-4 mobile-lg:grid-col-12">
<div class="usa-card__container">
<div class="img-container">
<img
src="{{ asset_url('images/internet.svg') }}"
alt=""
/>
</div>
<div class="usa-card__header padding-bottom-0">
<h3>Web-based</h3>
<div class="blue-bar"></div>
<img
src="{{ asset_url('images/internet.svg') }}"
alt="Globe on top of a web browser"
/>
<div class="usa-card__header">
<h3 class="font-heading-md">Web-based</h3>
</div>
<div class="usa-card__body">
<p>Nothing to download or install</p>
@@ -76,14 +81,13 @@ import usaButton %} {% block meta %}
</li>
<li class="usa-card tablet:grid-col-4 mobile-lg:grid-col-12">
<div class="usa-card__container">
<div class="img-container">
<img
src="{{ asset_url('images/fast.svg') }}"
alt=""
/>
</div>
<div class="usa-card__header padding-bottom-0">
<h3>Fast and easy</h3>
<div class="blue-bar"></div>
<img
src="{{ asset_url('images/fast.svg') }}"
alt="Stopwatch with a notification speech bubble with a star inside"
/>
<div class="usa-card__header">
<h3 class="font-heading-md">Fast and easy</h3>
</div>
<div class="usa-card__body">
<p>No technical expertise required</p>
@@ -92,14 +96,13 @@ import usaButton %} {% block meta %}
</li>
<li class="usa-card tablet:grid-col-4 mobile-lg:grid-col-12">
<div class="usa-card__container">
<div class="img-container">
<img
src="{{ asset_url('images/status.svg') }}"
alt=""
/>
</div>
<div class="usa-card__header padding-bottom-0">
<h3>Track message delivery</h3>
<div class="blue-bar"></div>
<img
src="{{ asset_url('images/status.svg') }}"
alt="3 status messages, 2 successes and one failure"
/>
<div class="usa-card__header">
<h3 class="font-heading-md">Track message delivery</h3>
</div>
<div class="usa-card__body">
<p>See which messages were received</p>
@@ -108,16 +111,17 @@ import usaButton %} {% block meta %}
</li>
</ul>
<ul class="usa-card-group">
<li class="usa-card tablet:grid-offset-2 tablet:grid-col-4 mobile-lg:grid-col-12">
<li class="usa-card tablet:grid-col-4 mobile-lg:grid-col-12">
<div class="usa-card__container">
<div class="img-container">
<img
src="{{ asset_url('images/translation.svg') }}"
alt=""
/>
</div>
<div class="usa-card__header padding-bottom-0">
<h3>Send in recipients' preferred language</h3>
<div class="blue-bar"></div>
<img
src="{{ asset_url('images/translation.svg') }}"
alt="Speech bubbles with the letter A and the Chinese character for language"
/>
<div class="usa-card__header">
<h3 class="font-heading-md">
Send in recipients' preferred language
</h3>
</div>
<div class="usa-card__body">
<p>Notify.gov has support for more than 30 character sets</p>
@@ -126,14 +130,31 @@ import usaButton %} {% block meta %}
</li>
<li class="usa-card tablet:grid-col-4 mobile-lg:grid-col-12">
<div class="usa-card__container">
<div class="img-container">
<img
src="{{ asset_url('images/send.svg') }}"
alt=""
/>
</div>
<div class="blue-bar"></div>
<img
src="{{ asset_url('images/security.svg') }}"
alt="Lock with code icon inside on top of a web browser"
/>
<div class="usa-card__header">
<h3 class="padding-bottom-0">
<h3 class="font-heading-md">Security and privacy</h3>
</div>
<div class="usa-card__body">
<p>
Limited data retention, encryption, and multi-factor
authentication protect user data and manage risk with <br><a href="/about/security">our security efforts</a>
</p>
</div>
</div>
</li>
<li class="usa-card tablet:grid-col-4 mobile-lg:grid-col-12">
<div class="usa-card__container">
<div class="blue-bar"></div>
<img
src="{{ asset_url('images/send.svg') }}"
alt="Paper airplane and a notification icon with the number 1 inside"
/>
<div class="usa-card__header">
<h3 class="font-heading-md">
Send bulk, customized, one-way messages
</h3>
</div>
@@ -149,52 +170,33 @@ import usaButton %} {% block meta %}
</div>
</section>
<section class="usa-section usa-section__home usa-prose security-and-privacy padding-y-6 bg-base-lighter">
<div class="grid-container">
<div class="grid-row flex-align-center flex-justify-center">
<div class="tablet:grid-col-7 mobile-lg:grid-col-12 margin-bottom-4">
<h2 class="font-heading-xl margin-top-0 margin-bottom-3">
Security and privacy
</h2>
<p class="usa-body margin-bottom-5">
Limited data retention, encryption, and multi-factor authentication protect user data and manage risk.
</p>
<a class="usa-button usa-button--big" href="/join-notify">Our security efforts</a>
<section
class="grid-container usa-section usa-section__home usa-prose grid-container padding-bottom-10">
<div class="grid-row grid-gap-3">
<a
class="text-no-underline tablet:grid-col-4 mobile-lg:grid-col-12"
href="mailto:tts-notify@gsa.gov"
>
<div class="contact-us-card">
<div class="grid-row flex-align-center grid-gap-2">
<div class="grid-col-auto">
<img
src="{{ asset_url('images/contact.svg') }}"
alt=""
class="height-7 width-7"
/>
</div>
<div class="grid-col">
<p class="margin-0">
<strong>Contact us</strong><br />
</p>
</div>
</div>
</div>
<div class="tablet:grid-col-3 mobile-lg:grid-col-12 display-flex flex-justify-center">
<img
class="width-card-lg"
src="{{ asset_url('images/security.svg') }}"
alt=""
/>
</div>
</div>
</a>
</div>
</section>
<section class="grid-container usa-section usa-section__home usa-prose margin-bottom-15">
<div class="grid-row flex-align-center flex-justify-center">
<div class="tablet:grid-col-4 mobile-lg:grid-col-12 display-flex flex-justify-center margin-right-8 margin-bottom-5">
<img src="{{ asset_url('images/product/who-can-use-notify.png') }}" alt="Woman smiling behind two computer screens"/>
</div>
<div class="tablet:grid-col-6 mobile-lg:grid-col-12">
<h2 class="font-heading-xl margin-top-0 margin-bottom-3">
Who can use Notify.gov?
</h2>
<p class="usa-body">
All <span class="text-bold">federal</span> agencies and programs are
eligible to use Notify.gov.
</p>
<p class="usa-body margin-bottom-5">
US
<span class="text-bold">state, local, territorial, or tribal</span>
governments that administer or deliver federally-funded programs or
services may qualify to use Notify.gov to communicate with applicants and
participants in these programs.
</p>
<a class="usa-button usa-button--big" href="/join-notify">Become a Notify.gov partner</a>
</div>
</section>
{% endblock %}
</main>
{% endblock %}

View File

@@ -15,7 +15,6 @@
<ul class="list list-bullet">
<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 details on pricing and what counts as a message part, see <a href={{ url_for("main.pricing") }}>Pricing</a>.</li>
</ul>
<p>If you have other questions, we are available at <a class="usa-link" href="mailto:notify-support@gsa.gov">notify-support@gsa.gov</a>.</p>

View File

@@ -12,16 +12,9 @@
<h2 class="font-body-lg">Limits while in trial mode</h2>
<p>While your service is in trial mode you can only:</p>
<ul class="list list-bullet">
<li>send 50 text message parts per day</li>
<li>send 50 text messages per day</li>
<li>send messages to yourself and other people in your team</li>
</ul>
<p>Each text message is made up of one or more parts.</p>
<ul class="list list-bullet">
<li>Generally, 160 characters is one part (and one text message).</li>
<li>A text message of 160-306 characters is two parts.</li>
</ul>
<p>For more information on how message parts are calculated, see
<a href="/using-notify/pricing">Tracking usage</a>.</p>
<h2 class="font-body-lg">Before going Live</h2>
<p>Before you request to make your service live so you can send messages to clients:</p>

Some files were not shown because too many files have changed in this diff Show More