From 062e0fb08c7a79b3a3c4c7b6f532334908c7d029 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:01:53 +0100 Subject: [PATCH 01/12] Bump prettier from 3.8.3 to 3.8.4 (#329) Bumps [prettier](https://github.com/prettier/prettier) from 3.8.3 to 3.8.4. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.8.3...3.8.4) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 70 ++++++++++------------------------------------- package.json | 2 +- 2 files changed, 16 insertions(+), 56 deletions(-) diff --git a/package-lock.json b/package-lock.json index c187cdf0..60868acb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "devDependencies": { "cssnano": "^8.0.1", "postcss": "^8.5.15", - "prettier": "^3.8.3", + "prettier": "^3.8.4", "purgecss": "^8.0.0" }, "engines": { @@ -1010,9 +1010,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1033,9 +1030,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1056,9 +1050,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1079,9 +1070,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1102,9 +1090,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1125,9 +1110,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1252,6 +1234,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz", "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } @@ -1269,15 +1252,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", - "peer": true, "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" @@ -1359,8 +1340,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/async": { "version": "2.6.4", @@ -1692,6 +1672,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -1811,6 +1792,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", + "peer": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1894,7 +1876,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 6" } @@ -2005,7 +1986,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -2604,6 +2584,7 @@ "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -2703,7 +2684,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -2802,7 +2782,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.6.0" } @@ -2873,7 +2852,6 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -2952,7 +2930,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -2962,7 +2939,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -3257,7 +3233,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.10" } @@ -3365,8 +3340,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/is-wsl": { "version": "1.1.0", @@ -3530,7 +3504,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -3666,7 +3639,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -3676,6 +3648,7 @@ "resolved": "https://registry.npmjs.org/nhsuk-frontend/-/nhsuk-frontend-10.5.2.tgz", "integrity": "sha512-lTOmzSDJkEn8uhuEuj3NKAW5MYuG/5tqMRsp15An2oLKlpGEoEAoREp+tHYJ7DLOPDRp9Z/zmp6/pLea75ae1g==", "license": "MIT", + "peer": true, "engines": { "node": "^20.9.0 || ^22.11.0 || >= 24.11.0" }, @@ -3900,7 +3873,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", - "peer": true, "dependencies": { "wrappy": "1" } @@ -3949,7 +3921,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -4029,6 +4000,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", @@ -4512,9 +4484,9 @@ } }, "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { @@ -4532,7 +4504,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", - "peer": true, "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -4777,7 +4748,6 @@ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -4878,6 +4848,7 @@ "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.100.0.tgz", "integrity": "sha512-Ut8wlQSk19tm7jMK6mz6cF1+e+E7tUnW2tM02zQDPnOTcVbV8qCQG8UWxZkkNlY50+hV3hqP24OOkUlMz8xBpw==", "license": "MIT", + "peer": true, "dependencies": { "@bufbuild/protobuf": "^2.5.0", "colorjs.io": "^0.5.0", @@ -5033,7 +5004,6 @@ "cpu": [ "arm" ], - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -5050,7 +5020,6 @@ "cpu": [ "arm64" ], - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -5067,7 +5036,6 @@ "cpu": [ "arm" ], - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -5084,7 +5052,6 @@ "cpu": [ "arm64" ], - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -5101,7 +5068,6 @@ "cpu": [ "riscv64" ], - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -5118,7 +5084,6 @@ "cpu": [ "x64" ], - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -5135,7 +5100,6 @@ "cpu": [ "riscv64" ], - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -5152,7 +5116,6 @@ "cpu": [ "x64" ], - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -5292,7 +5255,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", @@ -5433,7 +5395,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", - "peer": true, "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", @@ -6092,8 +6053,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/ws": { "version": "8.20.1", diff --git a/package.json b/package.json index c553e674..c9db3cca 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "devDependencies": { "cssnano": "^8.0.1", "postcss": "^8.5.15", - "prettier": "^3.8.3", + "prettier": "^3.8.4", "purgecss": "^8.0.0" } } From 0fb5e971ecf540d07f2545e7d2e06b31f4dd2ede Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:02:18 +0100 Subject: [PATCH 02/12] Bump cssnano from 8.0.1 to 8.0.2 (#330) Bumps [cssnano](https://github.com/cssnano/cssnano) from 8.0.1 to 8.0.2. - [Release notes](https://github.com/cssnano/cssnano/releases) - [Commits](https://github.com/cssnano/cssnano/compare/cssnano@8.0.1...cssnano@8.0.2) --- updated-dependencies: - dependency-name: cssnano dependency-version: 8.0.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 374 ++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 180 insertions(+), 196 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60868acb..206023e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "weighted": "^1.0.0" }, "devDependencies": { - "cssnano": "^8.0.1", + "cssnano": "^8.0.2", "postcss": "^8.5.15", "prettier": "^3.8.4", "purgecss": "^8.0.0" @@ -1397,9 +1397,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.34", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz", - "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==", + "version": "2.10.35", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.35.tgz", + "integrity": "sha512-honAfLBde0HAFLdNyBEfuuENkF6zR+ozxqxa/2zJKHBe1qzLqyTSeRKpdPEHAP03rlDGyQOPnCSxnVpVqQo9Mg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1732,22 +1732,20 @@ } }, "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-4.0.0.tgz", + "integrity": "sha512-B0hQ1OLyJuHTQSOWXvwibWqM6DCoqJdvBA6X1S/53bd4XU7LJ1yurIPlrsouol3mw1jh9pGI4ivubSpmJeIqCA==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "caniuse-lite": "^1.0.0" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001797", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", - "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", "dev": true, "funding": [ { @@ -2106,13 +2104,13 @@ } }, "node_modules/cssnano": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.1.tgz", - "integrity": "sha512-oSiOnPQNNYjusTUlYJiE6xvFQG4don3N0QavaoV1BxIsC1zjvxOwikXlR7lG1EVmZNDDaJkHbQx1VRB8kaoMHA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.2.tgz", + "integrity": "sha512-K+a76gA1v0/CsYgcsE95HGGyIuPKxpQSetwSwz4nHEM8fFXqSkzq2JzEXFL8v5+CCjxzVVVhPcTK3Oo8SaF/xA==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-preset-default": "^8.0.1", + "cssnano-preset-default": "^8.0.2", "lilconfig": "^3.1.3" }, "engines": { @@ -2123,64 +2121,64 @@ "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/cssnano-preset-default": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.1.tgz", - "integrity": "sha512-OTdKeYMlvQ8KBgyej5ysktnWJoeyo7rGrVnm+bdpIHGvxhbTGPsOkB+7T1EdTuX00dGlQQb2UEbSPB1OpMXULw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.2.tgz", + "integrity": "sha512-+jQAqIKCqMmBjZs7741XkilU93ITZ/EW8gjAkMmujdCzfDkfjrDBv2VqkSu29Fzeig/0rZ3S9IAwfPLlmXEUfQ==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-calc": "^10.1.1", - "postcss-colormin": "^8.0.0", - "postcss-convert-values": "^8.0.0", - "postcss-discard-comments": "^8.0.0", - "postcss-discard-duplicates": "^8.0.0", - "postcss-discard-empty": "^8.0.0", - "postcss-discard-overridden": "^8.0.0", - "postcss-merge-longhand": "^8.0.0", - "postcss-merge-rules": "^8.0.0", - "postcss-minify-font-values": "^8.0.0", - "postcss-minify-gradients": "^8.0.0", - "postcss-minify-params": "^8.0.0", - "postcss-minify-selectors": "^8.0.1", - "postcss-normalize-charset": "^8.0.0", - "postcss-normalize-display-values": "^8.0.0", - "postcss-normalize-positions": "^8.0.0", - "postcss-normalize-repeat-style": "^8.0.0", - "postcss-normalize-string": "^8.0.0", - "postcss-normalize-timing-functions": "^8.0.0", - "postcss-normalize-unicode": "^8.0.0", - "postcss-normalize-url": "^8.0.0", - "postcss-normalize-whitespace": "^8.0.0", - "postcss-ordered-values": "^8.0.0", - "postcss-reduce-initial": "^8.0.0", - "postcss-reduce-transforms": "^8.0.0", - "postcss-svgo": "^8.0.0", - "postcss-unique-selectors": "^8.0.0" + "postcss-colormin": "^8.0.1", + "postcss-convert-values": "^8.0.1", + "postcss-discard-comments": "^8.0.1", + "postcss-discard-duplicates": "^8.0.1", + "postcss-discard-empty": "^8.0.1", + "postcss-discard-overridden": "^8.0.1", + "postcss-merge-longhand": "^8.0.1", + "postcss-merge-rules": "^8.0.1", + "postcss-minify-font-values": "^8.0.1", + "postcss-minify-gradients": "^8.0.1", + "postcss-minify-params": "^8.0.1", + "postcss-minify-selectors": "^8.0.2", + "postcss-normalize-charset": "^8.0.1", + "postcss-normalize-display-values": "^8.0.1", + "postcss-normalize-positions": "^8.0.1", + "postcss-normalize-repeat-style": "^8.0.1", + "postcss-normalize-string": "^8.0.1", + "postcss-normalize-timing-functions": "^8.0.1", + "postcss-normalize-unicode": "^8.0.1", + "postcss-normalize-url": "^8.0.1", + "postcss-normalize-whitespace": "^8.0.1", + "postcss-ordered-values": "^8.0.1", + "postcss-reduce-initial": "^8.0.1", + "postcss-reduce-transforms": "^8.0.1", + "postcss-svgo": "^8.0.1", + "postcss-unique-selectors": "^8.0.1" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/cssnano-utils": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.0.tgz", - "integrity": "sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.1.tgz", + "integrity": "sha512-zk65GIxA8tCjqVk7nTm1mE+ZKxtnxAvU5JSUaBLXbAr3ZF7IOvz3fbPOnEDvZKhnS7GOIitXTS5BgehLzNoc8Q==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/csso": { @@ -2414,9 +2412,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.368", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz", - "integrity": "sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==", + "version": "1.5.371", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.371.tgz", + "integrity": "sha512-e9htk9mAYL6AzmkEhSvVVw7IWGSBJ/Bqdn2eRyRLrj1g6sncN4WbFt5qnILYoCktktr45pyjIrOiRvBThQ808w==", "dev": true, "license": "ISC" }, @@ -3427,20 +3425,6 @@ "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true, - "license": "MIT" - }, "node_modules/markdown-it": { "version": "14.2.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", @@ -4028,28 +4012,28 @@ } }, "node_modules/postcss-colormin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.0.tgz", - "integrity": "sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.1.tgz", + "integrity": "sha512-qBY4ABQ6d8/mk5RRZHwMllrZMxeMey3azVY2dZUEk+RgiUC4ARdPR3/AITzNqqKTbvW/3y/MJKinDrzwqn8RDQ==", "dev": true, "license": "MIT", "dependencies": { "@colordx/core": "^5.4.3", "browserslist": "^4.28.2", - "caniuse-api": "^3.0.0", + "caniuse-api": "^4.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-convert-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.0.tgz", - "integrity": "sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.1.tgz", + "integrity": "sha512-IdOSIX3BzfMvCc1TAHIha2gfy17xnb5vfML8e2BIKARnFOghksESfaSAB/3CXgyLfMozZAbTRPVQF5dbuKOidw==", "dev": true, "license": "MIT", "dependencies": { @@ -4060,104 +4044,104 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-discard-comments": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.0.tgz", - "integrity": "sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.1.tgz", + "integrity": "sha512-FDvzm3tXlEsQBO2XQgnta5ugsAqwBrgWH+j5QgXpegEIDYA0VPnZg2aP7LtmWtC49POskeIhXesFiU/k3NyFHA==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-discard-duplicates": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.0.tgz", - "integrity": "sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.1.tgz", + "integrity": "sha512-stTDXkI8YkCUfADurQhp03oq5ynsgSx6Qrw5B1swds6oTHtAeOZ9I0SHGK8cY/VpWUsIYFDWMs3IWf9jIEfFvA==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-discard-empty": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.0.tgz", - "integrity": "sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.1.tgz", + "integrity": "sha512-Zv4fM1Yfhk71tbt6gfiptbL6jDHi+7apSnaMeaO9n1uET+1embrXQw5m93Zp5x28UyQSuv+AVkFY193jdwZ33w==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-discard-overridden": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.0.tgz", - "integrity": "sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.1.tgz", + "integrity": "sha512-ykt4fvrC7yYGzbxKyqBVjDCbsjF/11JgWK8enrdkobRyqqEtb/uDUCbKOGdvrK8X7BrShW8Lv5cCRNbdkNHGkQ==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-merge-longhand": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.0.tgz", - "integrity": "sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.1.tgz", + "integrity": "sha512-huTfSYgQ13O81SFvAuOi7GWnO48vvybjj3xF+X3qUoPjzvvaLpJH5DcUqqXcwOEulZUcvaV4s0V9WtWs+IAQPA==", "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^8.0.0" + "stylehacks": "^8.0.1" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-merge-rules": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.0.tgz", - "integrity": "sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.1.tgz", + "integrity": "sha512-o3rk4UpnPNg469tklYwbR/NtvKc/f/wJiVDTnNQ/EFPw/LeiPOHUCvV1GIBQIZHGrBAYdPjToK6a+ojYprsrxQ==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^6.0.0", - "postcss-selector-parser": "^7.1.1" + "caniuse-api": "^4.0.0", + "cssnano-utils": "^6.0.1", + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-minify-font-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.0.tgz", - "integrity": "sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.1.tgz", + "integrity": "sha512-L8Nzs/PRlBSPrLdY/7rAiU5ZN5800+2J/4LRbfyG8SJnPljmgMaXVmQiCklvRS+yObfVRNtvmk/Ean/eoYcSeg==", "dev": true, "license": "MIT", "dependencies": { @@ -4167,81 +4151,81 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-minify-gradients": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.0.tgz", - "integrity": "sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.1.tgz", + "integrity": "sha512-qf+4s/hZMqTwpWN2teqf6+1yvR/SZK5HgHqXYuACeJXV7ABe7AXtBEomgxagUzcN4bSnmqBh5vnIml0dYqykYg==", "dev": true, "license": "MIT", "dependencies": { "@colordx/core": "^5.4.3", - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-minify-params": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.0.tgz", - "integrity": "sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.1.tgz", + "integrity": "sha512-L0h3H59deFfFg0wQN1NVaS/8E/LfGvaMuZKGO7siwlG995zo3OshtQyRkqKdVqcBwAORBvZ1nDZrKPLRapYkQw==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-minify-selectors": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.1.tgz", - "integrity": "sha512-c31D46811kTkQDxV1KTTow79axX6gj/01AY5G7cGZg3s31KvAwP13jEFXGAzQbJ7NvOFV1pRqEia6nrAdHU7qg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.2.tgz", + "integrity": "sha512-3icdxc/zght5UAizdwqZBDE2KOWHf1jMQCxET6iLACeNlRxfTPyXS0/COpGk8CQ2cECyaEKTRUd/i/k8Gxmz4g==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-api": "^3.0.0", + "caniuse-api": "^4.0.0", "cssesc": "^3.0.0", - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-charset": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.0.tgz", - "integrity": "sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.1.tgz", + "integrity": "sha512-xzqr36F8UeIZOvOHsf3aul+RVJCADvSwuwpMLgizqKjisHZpBfztgW0XFLBfJvz9pJgaStaOXAtGb0zLqT6B0w==", "dev": true, "license": "MIT", "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-display-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.0.tgz", - "integrity": "sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.1.tgz", + "integrity": "sha512-ZDWOijOK1FFMlpgiQCUO9fCNKd7HJ9L7z9HWEq4iyubnUFWzdTSwm/LcrMbNW6iZ1oAtqeLYA0WA3xHszOI08g==", "dev": true, "license": "MIT", "dependencies": { @@ -4251,13 +4235,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-positions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.0.tgz", - "integrity": "sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.1.tgz", + "integrity": "sha512-uuivan2poSqbE48ST4do20dGaFUeXey9/H8rhHzoyVHB2I6BmkoVLZ/C9+BRjUlpaAFYVOoDY7epkiidzaYbvA==", "dev": true, "license": "MIT", "dependencies": { @@ -4267,13 +4251,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.0.tgz", - "integrity": "sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.1.tgz", + "integrity": "sha512-q2hq5fmKxk29K6DjKA3nZ17Q2dtjhLYFNmFweKALmooUqx6UWAHF1bBoWTu/EqlJ88josb82A/J0Atj9LJUmpQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4283,13 +4267,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-string": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.0.tgz", - "integrity": "sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.1.tgz", + "integrity": "sha512-+Wf+kQJhm1WgSGEAuUaswE9rdpR9QbrKRVemcVHs6rhOoOTVIdAbgaicftfYA6vLM346P8onRzkEVbFN29ktKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4299,13 +4283,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.0.tgz", - "integrity": "sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.1.tgz", + "integrity": "sha512-W8/tvwRlm3T+yjGkg0IRTF4bvHj0vILYr/LOogCrJKHz2ey2HFRwfsAA8Bk9N4BGR7z7WmmDu/KzzwhJ6FoGPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4315,13 +4299,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-unicode": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.0.tgz", - "integrity": "sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.1.tgz", + "integrity": "sha512-Ad0YHNRBp4WHEOYUM/4wL/8MoL2fimEF8se/0q+Rt/owMzYpbxsypC1P8fN/oluwoRmRKdNVX7X2oycEobPWcQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4332,13 +4316,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.0.tgz", - "integrity": "sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.1.tgz", + "integrity": "sha512-tkYcip6pCDY806xuxpJYqMW2M3/623jzGFJmz3m5Us47q8P28+gbRZxaea3Rr/CmwwLUiVlh+BTGYwQ6gvaP8A==", "dev": true, "license": "MIT", "dependencies": { @@ -4348,13 +4332,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-normalize-whitespace": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.0.tgz", - "integrity": "sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.1.tgz", + "integrity": "sha512-XzORadNfSrKWDZZpgAEHPKINKx8r9r9RIfE9c70g/HThdpbmPHhDYCodHSVESDxmKeySAYw1p4liuBCf7j6LyA==", "dev": true, "license": "MIT", "dependencies": { @@ -4364,47 +4348,47 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-ordered-values": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.0.tgz", - "integrity": "sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.1.tgz", + "integrity": "sha512-OLXq5lR1yk3KWQ1FPK6aWjFFdktHE9f9kb8cnt4LmIw7w30DnzgD9+sOVYJc5HenkWCX8i1MJhhFwmqc/GYqLg==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-utils": "^6.0.0", + "cssnano-utils": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-reduce-initial": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.0.tgz", - "integrity": "sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.1.tgz", + "integrity": "sha512-+aQsR6+61KRoIfcFNLP3v9RM7+0iYOTtPnjl1wr6JqMW1zx6S+t2ktHRefXwacFdHIDj5+ETG0KY7K3+SGQ4Nw==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "caniuse-api": "^3.0.0" + "caniuse-api": "^4.0.0" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-reduce-transforms": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.0.tgz", - "integrity": "sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.1.tgz", + "integrity": "sha512-x71slHVykiFi5RuKEXM0wgYpY2PngC78x6R8TnZhHF3lhqt+u/w3MGwYLX+2t5O87ssRiMfEAhQH+3J4QwVzCw==", "dev": true, "license": "MIT", "dependencies": { @@ -4414,13 +4398,13 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-selector-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.3.tgz", + "integrity": "sha512-ajnd7iZnqjJDkyHNfznl/ZVO0lWqvBmQXfKKENx9/p/bEiF/L3eHwdydNUg9RXZx6xfZWOCmXmBa5oeB+YrAPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4432,9 +4416,9 @@ } }, "node_modules/postcss-svgo": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.0.tgz", - "integrity": "sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.1.tgz", + "integrity": "sha512-HpnvWii7W0/FPrsejJa6ZTi0kNtTJP/Iba7CUMPX0xPV6QpnndOp+SDP74tFtgjA2cYKYNWJPOlmLXMsvi/9yA==", "dev": true, "license": "MIT", "dependencies": { @@ -4445,23 +4429,23 @@ "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-unique-selectors": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.0.tgz", - "integrity": "sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.1.tgz", + "integrity": "sha512-+xvKI5+/Cl8yYQwxDV39Uhuc4WV951xngFvPPjiPj2NIbIfm6vbbRTXblyw0FioLkIoGlw+7qUcY1h2YhaZYgw==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/postcss-value-parser": { @@ -5695,20 +5679,20 @@ } }, "node_modules/stylehacks": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.0.tgz", - "integrity": "sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.1.tgz", + "integrity": "sha512-Gv095oTD0N+BdJALNFDsxZpETHZLTxbOl5RyIO7y6VAE6sR3z0MnV3Nix7N0IATNldNTrkvSASp2KR1Yt526HA==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.28.2", - "postcss-selector-parser": "^7.1.1" + "postcss-selector-parser": "^7.1.2" }, "engines": { "node": "^22.11.0 || ^24.11.0 || >=26.0" }, "peerDependencies": { - "postcss": "^8.5.14" + "postcss": "^8.5.15" } }, "node_modules/supports-color": { diff --git a/package.json b/package.json index c9db3cca..bcef20a1 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "npm": "^11.6.1" }, "devDependencies": { - "cssnano": "^8.0.1", + "cssnano": "^8.0.2", "postcss": "^8.5.15", "prettier": "^3.8.4", "purgecss": "^8.0.0" From 581e6ef993c3400d47e2abb0d939013bf32261ce Mon Sep 17 00:00:00 2001 From: Danny Chadburn Date: Fri, 12 Jun 2026 16:57:19 +0100 Subject: [PATCH 03/12] Various updates to previous mammogram form and summary (#327) * Update hint text for previous mammogram form * Update subHeading for mammogram history section * Update mammogram history display text and conditions * Update location labels for mammogram data * Update date formatting for mammogram records * Update app/views/_includes/medical-information/mammogram-history.njk --- app/lib/utils/prior-mammograms.js | 18 ++++++++---------- .../_includes/medical-information/index.njk | 4 ++-- .../medical-information/mammogram-history.njk | 9 +++------ app/views/events/previous-mammograms/form.html | 2 +- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/app/lib/utils/prior-mammograms.js b/app/lib/utils/prior-mammograms.js index 2dc56105..86d753aa 100644 --- a/app/lib/utils/prior-mammograms.js +++ b/app/lib/utils/prior-mammograms.js @@ -129,21 +129,19 @@ const summarisePriorMammogram = (mammogram, options = {}) => { let location = '' switch (mammogram.location) { case 'bsu': - location = mammogram.bsu || 'NHS breast screening unit' + location = 'At another BSU' break case 'otherUk': - location = mammogram.otherUk || 'Other UK location' + location = 'Elsewhere in the UK' break case 'otherNonUk': - location = mammogram.otherNonUk - ? `Outside UK: ${mammogram.otherNonUk}` - : 'Outside UK' + location = 'Outside the UK' break case 'currentBsu': - location = unitName || 'Current BSU' + location = `At ${unitName || 'this BSU'}` break case 'preferNotToSay': - location = 'Location not given' + location = 'Location not provided' break default: location = '' @@ -152,14 +150,14 @@ const summarisePriorMammogram = (mammogram, options = {}) => { // Date detail — combine formatted date and relative time into parenthesised suffix const dateParts = [] if (mammogram.dateType === 'dateKnown' && mammogram.dateTaken) { - dateParts.push(formatDate(mammogram.dateTaken, 'MMMM YYYY')) + dateParts.push(formatDate(mammogram.dateTaken, 'MMM YYYY')) if (mammogram._rawDate) { dateParts.push(formatRelativeDate(mammogram._rawDate)) } } else if (mammogram.dateType === 'moreThanSixMonths') { - dateParts.push(mammogram.approximateDate || 'over 6 months ago') + dateParts.push('over 6 months ago') } else if (mammogram.dateType === 'lessThanSixMonths') { - dateParts.push(mammogram.approximateDate || 'less than 6 months ago') + dateParts.push('less than 6 months ago') } const dateDetail = dateParts.length > 0 ? `(${dateParts.join(', ')})` : '' diff --git a/app/views/_includes/medical-information/index.njk b/app/views/_includes/medical-information/index.njk index eedbcb8e..b0849ca3 100644 --- a/app/views/_includes/medical-information/index.njk +++ b/app/views/_includes/medical-information/index.njk @@ -12,7 +12,7 @@ {# Mammogram history #} {% set sectionHeading = "Mammogram history" %} -{% set subHeading = "The last confirmed mammogram and any added manually since then" %} +{% set subHeading = "Previous mammograms from screening records and any reported by the participant" %} {% set sectionId = sectionHeading | kebabCase %} {% set scrollTo = sectionId %} @@ -275,4 +275,4 @@ html: otherRelevantInformationHtml, status: "To review" }) }} -{% endswitch %} \ No newline at end of file +{% endswitch %} diff --git a/app/views/_includes/medical-information/mammogram-history.njk b/app/views/_includes/medical-information/mammogram-history.njk index da6e6e47..46b52967 100644 --- a/app/views/_includes/medical-information/mammogram-history.njk +++ b/app/views/_includes/medical-information/mammogram-history.njk @@ -3,9 +3,6 @@ {% set hasAdditionalMammograms = event.previousMammograms | length > 0 %} {# System record - last known mammogram from BSU records #} -{% if hasAdditionalMammograms %} -

From screening records

-{% endif %} {% set systemRecordHtml %} {% set mostRecentClinic = data | getParticipantMostRecentClinic(participant.id) %} @@ -15,7 +12,7 @@ {{ mostRecentClinic.location.name }}
{{ mostRecentClinic.event.type | sentenceCase }} {% else %} - {{ "Not known" | asHint }} + {{ "No information" | asHint }} {% endif %} {% endset %} @@ -23,7 +20,7 @@ rows: [ { key: { - text: "Last known mammogram" + text: "Most recent mammogram on record" }, value: { html: systemRecordHtml @@ -126,4 +123,4 @@ {{ summaryList({ rows: userMammogramRows } | openInModal | removeLastRowBorder) }} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/app/views/events/previous-mammograms/form.html b/app/views/events/previous-mammograms/form.html index e1a9f166..78098e9b 100644 --- a/app/views/events/previous-mammograms/form.html +++ b/app/views/events/previous-mammograms/form.html @@ -289,7 +289,7 @@

}, value: event.previousMammogramTemp.otherDetails, hint: { - text: "For example, the reason for the mammograms and the outcome of the assessment" + text: "For example, the reason for the mammogram, the participant's previous address, and the outcome of the assessment" } }) }} From 9b05498fdf3fb2985b4a20b45259b212181181a8 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Fri, 12 Jun 2026 17:00:04 +0100 Subject: [PATCH 04/12] Defer reading a case (#331) * Initial work on deferring a case * Fixes to deferral route * Improve deferral dashboard * Apply suggestions from code review Co-authored-by: Danny Chadburn --------- Co-authored-by: Danny Chadburn --- app/lib/utils/reading.js | 24 ++- app/lib/utils/status.js | 1 + app/routes/events.js | 11 ++ app/routes/reading.js | 167 ++++++++++++++++- .../_includes/reading/reading-status-bar.njk | 3 + app/views/reading/deferred.html | 168 ++++++++++++++++++ app/views/reading/index-complex.html | 26 ++- app/views/reading/index-simple.html | 44 ++++- app/views/reading/session.html | 14 +- app/views/reading/workflow/defer-case.html | 50 ++++++ app/views/reading/workflow/existing-read.html | 49 ++++- app/views/reading/workflow/opinion.html | 12 +- .../reading/workflow/request-priors.html | 15 +- app/views/settings.html | 2 +- 14 files changed, 543 insertions(+), 43 deletions(-) create mode 100644 app/views/reading/deferred.html create mode 100644 app/views/reading/workflow/defer-case.html diff --git a/app/lib/utils/reading.js b/app/lib/utils/reading.js index acc88ace..491b3b23 100644 --- a/app/lib/utils/reading.js +++ b/app/lib/utils/reading.js @@ -1366,6 +1366,16 @@ const shouldShowComparePage = function ( * @param {object} [options] - Options for determining eligibility * @returns {boolean} Whether the current user can read this event */ +/** + * Check if an event has been deferred from reading + * + * @param {object} event - The event to check + * @returns {boolean} Whether the event has been deferred + */ +const isDeferred = (event) => { + return !!event?.imageReading?.deferral?.deferredAt +} + const canUserReadEvent = function (event, userId = null, options = {}) { const { maxReadsPerEvent = 2 } = options @@ -1383,6 +1393,11 @@ const canUserReadEvent = function (event, userId = null, options = {}) { return false } + // Can't read if event has been deferred + if (isDeferred(event)) { + return false + } + const metadata = getReadingMetadata(event) // If we already have enough unique readers, no more reads needed @@ -1821,17 +1836,23 @@ const getSessionReadingProgress = ( const resolvedTargetSize = session.targetSize || sessionEvents.length + // Count deferred events so they count toward the session target + const deferredCount = sessionEvents.filter(isDeferred).length + return { ...progress, // How many events are currently loaded vs the overall target populatedCount: sessionEvents.length, targetSize: resolvedTargetSize, + // Deferred events count as 'done' for session progress purposes + deferredCount, // Remaining reads against the target (not just currently loaded events) targetRemaining: Math.max( 0, resolvedTargetSize - progress.userReadCount - - progress.userAwaitingPriorsCount + progress.userAwaitingPriorsCount - + deferredCount ) } } @@ -1884,6 +1905,7 @@ module.exports = { // Booleans userHasReadEvent, canUserReadEvent, + isDeferred, hasReads, needsArbitration, needsFirstRead, diff --git a/app/lib/utils/status.js b/app/lib/utils/status.js index 37e833ab..6937927e 100644 --- a/app/lib/utils/status.js +++ b/app/lib/utils/status.js @@ -283,6 +283,7 @@ const getStatusTagColour = (status) => { 'prior_pending': 'orange', 'prior_requested': 'yellow', 'priors_requested': 'yellow', + 'deferred': 'orange', 'prior_received': 'green', 'prior_not_available': 'grey', 'prior_not_needed': 'grey' diff --git a/app/routes/events.js b/app/routes/events.js index 1f5e5bd2..9e59c800 100644 --- a/app/routes/events.js +++ b/app/routes/events.js @@ -804,6 +804,17 @@ module.exports = (router) => { return res.redirect(modalBreakout(`/clinics/${clinicId}/`)) } + // Normalise approximateDate in session now, before any redirect, so the + // warning page doesn't display a raw array (e.g. ",June 2025") caused by + // both conditional inputs being submitted together. + if ( + previousMammogramTemp && + Array.isArray(previousMammogramTemp.approximateDate) + ) { + previousMammogramTemp.approximateDate = + previousMammogramTemp.approximateDate.find((v) => v) || '' + } + // Check if this is a recent mammogram (within 6 months) const isRecentMammogram = checkIfRecentMammogram(previousMammogramTemp) diff --git a/app/routes/reading.js b/app/routes/reading.js index 919c95cb..3631637b 100644 --- a/app/routes/reading.js +++ b/app/routes/reading.js @@ -40,9 +40,8 @@ module.exports = (router) => { // Reading index — choose layout based on setting router.get('/reading', (req, res) => { const layout = req.session.data?.settings?.reading?.indexLayout || 'simple' - const template = layout === 'complex' - ? 'reading/index-complex' - : 'reading/index-simple' + const template = + layout === 'complex' ? 'reading/index-complex' : 'reading/index-simple' res.render(template) }) @@ -550,6 +549,14 @@ module.exports = (router) => { ) } + // Check if event has been deferred from reading + const { isDeferred } = require('../lib/utils/reading') + if (isDeferred(event)) { + return res.redirect( + `/reading/session/${sessionId}/events/${eventId}/existing-read` + ) + } + // Delete temporary data from previous steps delete data.imageReadingTemp @@ -653,12 +660,16 @@ module.exports = (router) => { editHref: `/reading/session/${sessionId}/events/${eventId}/existing-read` } res.redirect( - `/reading/session/${sessionId}/events/${nextUnreadEvent.id}` + modalBreakout( + `/reading/session/${sessionId}/events/${nextUnreadEvent.id}` + ) ) } else if (session.skippedEvents.length > 0) { - res.redirect(`/reading/session/${sessionId}/skipped-review`) + res.redirect( + modalBreakout(`/reading/session/${sessionId}/skipped-review`) + ) } else { - res.redirect(`/reading/session/${sessionId}`) + res.redirect(modalBreakout(`/reading/session/${sessionId}`)) } } ) @@ -698,6 +709,143 @@ module.exports = (router) => { } ) + /************************************************************************ + // Case deferral + /***********************************************************************/ + + // Handle deferring a case from reading + router.post( + '/reading/session/:sessionId/events/:eventId/defer-case-answer', + (req, res) => { + const data = req.session.data + const { sessionId, eventId } = req.params + const currentUserId = data.currentUser?.id + + const reason = req.body.deferralReason || '' + + // Find the event and save deferral data + const event = data.events.find((e) => e.id === eventId) + if (event) { + if (!event.imageReading) { + event.imageReading = {} + } + + // Remove any existing read by this user — deferral replaces a prior opinion + if (event.imageReading.reads?.[currentUserId]) { + delete event.imageReading.reads[currentUserId] + } + + event.imageReading.deferral = { + deferredAt: new Date().toISOString(), + deferredBy: currentUserId, + reason: reason || null + } + + // Also update the mirrored event in data.event + if (data.event && data.event.id === eventId) { + data.event.imageReading = event.imageReading + } + } + + // Top up the session with the next eligible event if under target size + topUpSession(data, sessionId) + + // Find next readable event after current position + const session = getReadingSession(data, sessionId) + const sessionEvents = session.eventIds + .map((id) => data.events.find((e) => e.id === id)) + .filter(Boolean) + const nextUnreadEvent = getNextUserReadableEvent( + sessionEvents, + eventId, + currentUserId, + { wrap: false } + ) + + // Show a banner on the next case if there is one + if (nextUnreadEvent) { + const participant = data.participants.find( + (person) => person.id === event?.participantId + ) + const shortName = getShortName(participant) + data.readingOpinionBanner = { + text: `Case deferred for ${shortName}`, + participantName: shortName, + editHref: `/reading/session/${sessionId}/events/${eventId}/existing-read` + } + res.redirect( + modalBreakout( + `/reading/session/${sessionId}/events/${nextUnreadEvent.id}` + ) + ) + } else if (session.skippedEvents.length > 0) { + res.redirect( + modalBreakout(`/reading/session/${sessionId}/skipped-review`) + ) + } else { + res.redirect(modalBreakout(`/reading/session/${sessionId}`)) + } + } + ) + + // Undo a case deferral — removes the deferral so the case returns to reading + router.all( + '/reading/session/:sessionId/events/:eventId/undo-defer', + (req, res) => { + const data = req.session.data + const { sessionId, eventId } = req.params + + const event = data.events.find((e) => e.id === eventId) + if (event?.imageReading?.deferral) { + delete event.imageReading.deferral + + // Also update the mirrored event in data.event + if (data.event && data.event.id === eventId) { + data.event.imageReading = event.imageReading + } + } + + res.redirect(`/reading/session/${sessionId}/events/${eventId}/opinion`) + } + ) + + // Deferred cases management page + router.get('/reading/deferred', (req, res) => { + res.render('reading/deferred') + }) + + // Unflag a deferral from the deferred cases management page + // Keeps a record of the resolved deferral so the reason stays visible + router.post('/reading/deferred/undo', (req, res) => { + const data = req.session.data + const { eventId } = req.body + + const event = data.events.find((e) => e.id === eventId) + if (event?.imageReading?.deferral) { + if (!event.imageReading.deferralHistory) { + event.imageReading.deferralHistory = [] + } + event.imageReading.deferralHistory.push({ + ...event.imageReading.deferral, + resolvedAt: new Date().toISOString(), + resolvedBy: data.currentUser?.id + }) + delete event.imageReading.deferral + + if (data.event && data.event.id === eventId) { + data.event.imageReading = event.imageReading + } + + const participant = data.participants.find( + (p) => p.id === event.participantId + ) + const shortName = getShortName(participant) + req.flash('success', `${shortName} returned to reading queue`) + } + + res.redirect('/reading/deferred') + }) + // Render appropriate template for reading views router.get( '/reading/session/:sessionId/events/:eventId/:step', @@ -719,6 +867,7 @@ module.exports = (router) => { 'existing-read', 'compare', 'request-priors', + 'defer-case', 'medical-information' ] @@ -1311,7 +1460,8 @@ module.exports = (router) => { for (const side of ['right', 'left']) { const assessment = side === 'right' ? rightAssessment : leftAssessment - const annotations = side === 'right' ? rightAnnotations : leftAnnotations + const annotations = + side === 'right' ? rightAnnotations : leftAnnotations const sideLabel = side if (!assessment) continue @@ -1352,8 +1502,7 @@ module.exports = (router) => { }) } } - } - else if (assessment === 'normal' || assessment === 'clinical') { + } else if (assessment === 'normal' || assessment === 'clinical') { // Normal/clinical breast must not have annotations of M3 or higher if (highLevelAnnotations.length > 0) { errors.push({ diff --git a/app/views/_includes/reading/reading-status-bar.njk b/app/views/_includes/reading/reading-status-bar.njk index 1cb32a52..39623ce4 100644 --- a/app/views/_includes/reading/reading-status-bar.njk +++ b/app/views/_includes/reading/reading-status-bar.njk @@ -32,6 +32,9 @@ {%- if progress.userAwaitingPriorsCount > 0 -%} , {{ progress.userAwaitingPriorsCount }} awaiting priors {%- endif -%} + {%- if progress.deferredCount > 0 -%} + , {{ progress.deferredCount }} deferred + {%- endif -%} , {{ progress.targetRemaining }} remaining {%- if progress.skippedEvents | length > 0 %} ({{ progress.skippedEvents | length }} skipped) diff --git a/app/views/reading/deferred.html b/app/views/reading/deferred.html new file mode 100644 index 00000000..22398762 --- /dev/null +++ b/app/views/reading/deferred.html @@ -0,0 +1,168 @@ +{# app/views/reading/deferred.html #} + +{% extends 'layout-app.html' %} + +{% from '_components/summary-list/macro.njk' import appSummaryList %} + +{% set pageHeading = "Deferred cases" %} +{% set gridColumn = "nhsuk-grid-column-two-thirds" %} + +{% set back = { + href: "/reading", + text: "Back" +} %} + +{% block pageContent %} + + {# Get all events that have been deferred #} + {% set deferredEvents = [] %} + {% for thisEvent in data.events %} + {% if thisEvent | isDeferred %} + {% set deferredEvents = deferredEvents | push(thisEvent) %} + {% endif %} + {% endfor %} + + {# Sort by deferral date, most recent first #} + {% set deferredEvents = deferredEvents | sort(true, false, 'imageReading.deferral.deferredAt') %} + + {# Collect resolved deferrals across all events, most recently resolved first #} + {% set resolvedDeferrals = [] %} + {% for thisEvent in data.events %} + {% for pastDeferral in thisEvent.imageReading.deferralHistory %} + {% set resolvedDeferrals = resolvedDeferrals | push({ event: thisEvent, deferral: pastDeferral }) %} + {% endfor %} + {% endfor %} + {% set resolvedDeferrals = resolvedDeferrals | sort(true, false, 'deferral.resolvedAt') %} + + Image reading +

{{ pageHeading }}

+ +

Cases deferred from reading require manual review before they can be returned to the reading queue.

+ + {% if deferredEvents | length == 0 %} +

No deferred cases.

+ {% else %} + + {% for thisEvent in deferredEvents %} + {% set thisParticipant = data | getParticipant(thisEvent.participantId) %} + {% set deferral = thisEvent.imageReading.deferral %} + + {% set screenedHtml %} + {% set daysSinceScreening = thisEvent.timing.startTime | daysSince %} + {% if daysSinceScreening >= data.config.reading.urgentThreshold %} + {{ "Urgent" | toTag }}
+ {% elseif daysSinceScreening >= data.config.reading.priorityThreshold %} + {{ "Due soon" | toTag }}
+ {% endif %} + {{ thisEvent.timing.startTime | formatDate }} + ({{ thisEvent.timing.startTime | formatRelativeDate }}) + {% endset %} + + {% set deferredHtml %} + {{ deferral.deferredAt | formatDate("D MMM YYYY") }} + ({{ deferral.deferredAt | formatRelativeDate }}) + {% endset %} + + {% set reasonHtml %} + {% if deferral.reason %} + {{ deferral.reason }} + {% else %} + No reason given + {% endif %} + {% if deferral.deferredBy %} +
+ + {{ deferral.deferredBy | getUsername({ format: "short", identifyCurrentUser: true }) }} + + {% endif %} + {% endset %} + +
+
+

+ + {{ thisParticipant | getFullName }} + +

+
+
+ + +
+
+
+
+ {{ appSummaryList({ + rows: [ + { key: { text: "Screened" }, value: { html: screenedHtml } }, + { key: { text: "Deferred" }, value: { html: deferredHtml } }, + { key: { text: "Reason" }, value: { html: reasonHtml } } + ] + }) }} +
+
+ {% endfor %} + + {% endif %} + + {% if resolvedDeferrals | length > 0 %} + +

Recently resolved

+

These cases have been unflagged and returned to the reading queue.

+ + {% for row in resolvedDeferrals %} + {% set thisEvent = row.event %} + {% set deferral = row.deferral %} + {% set thisParticipant = data | getParticipant(thisEvent.participantId) %} + + {% set deferredHtml %} + {{ deferral.deferredAt | formatDate("D MMM YYYY") }} + ({{ deferral.deferredAt | formatRelativeDate }}) + {% endset %} + + {% set reasonHtml %} + {% if deferral.reason %} + {{ deferral.reason }} + {% else %} + No reason given + {% endif %} + {% if deferral.deferredBy %} +
+ + {{ deferral.deferredBy | getUsername({ format: "short", identifyCurrentUser: true }) }} + + {% endif %} + {% endset %} + + {% set resolvedHtml %} + {{ deferral.resolvedAt | formatDate("D MMM YYYY") }} + {% if deferral.resolvedBy %} + by {{ deferral.resolvedBy | getUsername({ format: "short", identifyCurrentUser: true }) }} + {% endif %} + {% endset %} + +
+ +
+ {{ appSummaryList({ + rows: [ + { key: { text: "Deferred" }, value: { html: deferredHtml } }, + { key: { text: "Reason" }, value: { html: reasonHtml } }, + { key: { text: "Returned to queue" }, value: { html: resolvedHtml } } + ] + }) }} +
+
+ {% endfor %} + + {% endif %} + +{% endblock %} diff --git a/app/views/reading/index-complex.html b/app/views/reading/index-complex.html index 2ec79f03..5bd5475b 100644 --- a/app/views/reading/index-complex.html +++ b/app/views/reading/index-complex.html @@ -12,17 +12,21 @@

{{ pageHeading }}

Start new reading session

-{# Awaiting priors not automatically filtered #} +{# Awaiting priors — count across all eligible events, not just those needing reads #} +{% set awaitingPriorsEvents = [] %} +{% for thisEvent in data.events | filterEventsByEligibleForReading %} + {% if thisEvent | awaitingPriors %} + {% set awaitingPriorsEvents = awaitingPriorsEvents | push(thisEvent) %} + {% endif %} +{% endfor %} + {% set allReadsEventsWithAwaitingPriors = data.events | filterEventsByEligibleForReading | filterEventsByNeedsAnyRead | sortEventsByScreeningDate %} -{# Split into awaiting priors and available for reading #} +{# Split readable events into awaiting priors and available for reading #} {# Events with 'requested' status mammograms are held from reading #} {% set allReadsEvents = [] %} -{% set awaitingPriorsEvents = [] %} {% for thisEvent in allReadsEventsWithAwaitingPriors %} - {% if thisEvent | awaitingPriors %} - {% set awaitingPriorsEvents = awaitingPriorsEvents | push(thisEvent) %} - {% else %} + {% if not (thisEvent | awaitingPriors) %} {% set allReadsEvents = allReadsEvents | push(thisEvent) %} {% endif %} {% endfor %} @@ -70,7 +74,7 @@

Start new reading session

{% endif %} - {% set defaultSessionSize = 25 %} + {% set defaultSessionSize = data.settings.reading.defaultSessionSize or 25 %} {% set maxCases = allReadCount if allReadCount < defaultSessionSize else defaultSessionSize %} {% set actionLinkHtml %} @@ -172,6 +176,14 @@

Other options

href: "/reading/priors" }) }} +
  • + {{ card({ + heading: "Deferred cases", + headingClasses: "nhsuk-heading-s", + clickable: true, + href: "/reading/deferred" + }) }} +
  • {{ card({ heading: "Reading statistics", diff --git a/app/views/reading/index-simple.html b/app/views/reading/index-simple.html index 7e5bccab..21e702e5 100644 --- a/app/views/reading/index-simple.html +++ b/app/views/reading/index-simple.html @@ -7,7 +7,7 @@ {% set gridColumn = "none" %} {% set currentUserId = data.currentUser.id %} -{% set defaultSessionSize = 25 %} +{% set defaultSessionSize = data.settings.reading.defaultSessionSize or 25 %} {# Build a list of the current user's sessions, most-recent first. @@ -71,6 +71,20 @@ {% endif %} {% endfor %} +{% set deferredCount = 0 %} +{% for thisEvent in data.events %} + {% if thisEvent | isDeferred %} + {% set deferredCount = deferredCount + 1 %} + {% endif %} +{% endfor %} + +{% set awaitingPriorsCount = 0 %} +{% for thisEvent in data.events | filterEventsByEligibleForReading %} + {% if thisEvent | awaitingPriors %} + {% set awaitingPriorsCount = awaitingPriorsCount + 1 %} + {% endif %} +{% endfor %} + {% set newlyArrivedPriorsCount = 2 %} {% set actionTotal = arbitrationCount + newlyArrivedPriorsCount %} @@ -115,17 +129,31 @@

    Start image reading

    {% endif %} - {% if actionTotal > 0 %} + {# Awaiting priors inset #} + {% if awaitingPriorsCount > 0 %} + {% set insetHtml %} +

    {{ awaitingPriorsCount }} {{ "case" if awaitingPriorsCount == 1 else "cases" }} awaiting priors

    +

    These cases are on hold pending prior mammogram images.

    +

    Manage prior mammograms

    + {% endset %} + {{ insetText({ + html: insetHtml | safe + }) }} + {% endif %} + + {# Deferred cases inset #} + {% if deferredCount > 0 %} {% set insetHtml %} -

    {{ actionTotal }} flagged {{ "case" if actionTotal == 1 else "cases" }}

    -

    Flagged cases require action before they can be read.

    -

    Review flagged cases

    +

    {{ deferredCount }} deferred {{ "case" if deferredCount == 1 else "cases" }}

    +

    Deferred cases require review before they can be returned to the reading queue.

    +

    Review deferred cases

    {% endset %} {{ insetText({ html: insetHtml | safe }) }} {% endif %} + {# Previous sessions inset #} {% if previousSessions | length > 0 %}

    Your previous image reading sessions

      @@ -140,10 +168,8 @@

      Your previous image reading sessions

      See all

      {% endif %} - - -
      -
      + + {% endblock %} diff --git a/app/views/reading/session.html b/app/views/reading/session.html index 3a169468..5356a2bf 100644 --- a/app/views/reading/session.html +++ b/app/views/reading/session.html @@ -104,7 +104,7 @@

      {# YOUR READS VIEW - Shows cases from user's perspective #} {% set userReadableEvents = [] %} {% for event in events %} - {% if event | canUserReadEvent or event | userHasReadEvent or event | userRequestedPriors(data.currentUser.id) %} + {% if event | canUserReadEvent or event | userHasReadEvent or event | userRequestedPriors(data.currentUser.id) or event | isDeferred %} {% set userReadableEvents = userReadableEvents | push(event) %} {% endif %} {% endfor %} @@ -118,6 +118,7 @@

      {% set technicalRecallEvents = [] %} {% set recallForAssessmentEvents = [] %} {% set priorsRequestedEvents = [] %} + {% set deferredEvents = [] %} {% for event in userReadableEvents %} {% if event | userHasReadEvent %} @@ -131,6 +132,8 @@

      {% endif %} {% elseif event | userRequestedPriors(data.currentUser.id) %} {% set priorsRequestedEvents = priorsRequestedEvents | push(event) %} + {% elseif event | isDeferred %} + {% set deferredEvents = deferredEvents | push(event) %} {% endif %} {% endfor %} @@ -139,6 +142,7 @@

      {% set technicalRecallCount = technicalRecallEvents | length %} {% set recallForAssessmentCount = recallForAssessmentEvents | length %} {% set priorsRequestedCount = priorsRequestedEvents | length %} + {% set deferredCount = deferredEvents | length %} {% set normalPercent = (normalCount / totalCount * 100) | round %} {% set technicalRecallPercent = (technicalRecallCount / totalCount * 100) | round %} @@ -213,10 +217,10 @@

      Opinion summary

      {% endif %}

      Reading session cases

      - {% set userSessionRemainingCount = session.targetSize - readingStatus.userReadCount - readingStatus.userAwaitingPriorsCount %} + {% set userSessionRemainingCount = session.targetSize - readingStatus.userReadCount - readingStatus.userAwaitingPriorsCount - deferredCount %} {% set userSessionRemainingCount = 0 if userSessionRemainingCount < 0 else userSessionRemainingCount %} - {% if userSessionRemainingCount > 0 or readingStatus.userAwaitingPriorsCount > 0 %} -

      Progress: {{ readingStatus.userReadCount }} read{%- if readingStatus.userAwaitingPriorsCount > 0 -%}, {{ readingStatus.userAwaitingPriorsCount }} awaiting priors{%- endif -%}, {{ userSessionRemainingCount }} remaining

      + {% if userSessionRemainingCount > 0 or readingStatus.userAwaitingPriorsCount > 0 or deferredCount > 0 %} +

      Progress: {{ readingStatus.userReadCount }} read{%- if readingStatus.userAwaitingPriorsCount > 0 -%}, {{ readingStatus.userAwaitingPriorsCount }} awaiting priors{%- endif -%}{%- if deferredCount > 0 -%}, {{ deferredCount }} deferred{%- endif -%}, {{ userSessionRemainingCount }} remaining

      {% endif %} @@ -288,6 +292,8 @@

      Reading session cases

      {% if read.opinion %} {{ read.opinion | toTag }} {% endif %} + {% elseif event | isDeferred %} + {{ "Deferred" | toTag }} {% elseif event | userRequestedPriors(data.currentUser.id) %} {{ "Priors requested" | toTag }} {% elseif session.skippedEvents | includes(event.id) %} diff --git a/app/views/reading/workflow/defer-case.html b/app/views/reading/workflow/defer-case.html new file mode 100644 index 00000000..48515a08 --- /dev/null +++ b/app/views/reading/workflow/defer-case.html @@ -0,0 +1,50 @@ +{# app/views/reading/workflow/defer-case.html #} + +{% extends parentLayout or 'layout-reading.html' %} + +{% set pageHeading = "Defer this case" %} +{% set formAction = './defer-case-answer' | urlWithReferrer(referrerChain) %} +{% set back = { + href: "./opinion", + text: "Back" +} %} + +{% block pageContent %} + + {% set caption %} + {{ participant | getFullName }} + {% endset %} + +
      +
      + +

      + {{ caption }} + {{ pageHeading }} +

      + +

      + This case will be removed from the reading queue. It must be manually reviewed before it can be read. +

      + + {{ textarea({ + name: "deferralReason", + id: "deferralReason", + label: { + text: "Reason for deferring", + size: "s" + }, + hint: { + text: "Explain why you are unable to give an opinion on this case" + }, + rows: 4 + }) }} + + {{ button({ + text: "Confirm deferral" + }) }} + +
      +
      + +{% endblock %} diff --git a/app/views/reading/workflow/existing-read.html b/app/views/reading/workflow/existing-read.html index 2f2e41ae..d4b1c4fe 100644 --- a/app/views/reading/workflow/existing-read.html +++ b/app/views/reading/workflow/existing-read.html @@ -10,12 +10,59 @@ {% set isAwaitingPriors = event | awaitingPriors %} {% set hasUserRead = event | userHasReadEvent %} + {% set isDeferredCase = event | isDeferred %} {{ participant | getFullName }} - {% if isAwaitingPriors and not hasUserRead %} + {% if isDeferredCase and not hasUserRead %} + {# Event has been deferred - show deferral summary #} +

      Your opinion

      + + {% set deferral = event.imageReading.deferral %} + {% set canUndo = deferral.deferredBy == data.currentUser.id %} + + {% set deferralSummaryHtml %} + {% call appSummaryList() %} + {{ appSummaryListRow({ + key: { + text: "Opinion" + }, + value: { + html: "Deferred" | toTag + }, + actions: { + items: [{ + href: "./undo-defer", + text: "Undo deferral", + visuallyHiddenText: "case deferral" + }] + } if canUndo + }) }} + + {% if deferral.reason %} + {{ appSummaryListRow({ + key: { + text: "Reason" + }, + value: { + text: deferral.reason + } + }) }} + {% endif %} + + {% endcall %} + {% endset %} + + {{ card({ + heading: "Your read", + headingLevel: "2", + feature: true, + descriptionHtml: deferralSummaryHtml + }) }} + + {% elseif isAwaitingPriors and not hasUserRead %} {# Event is awaiting priors - show as the reader's opinion #}

      Your opinion

      diff --git a/app/views/reading/workflow/opinion.html b/app/views/reading/workflow/opinion.html index 96279889..e5e4e659 100644 --- a/app/views/reading/workflow/opinion.html +++ b/app/views/reading/workflow/opinion.html @@ -153,7 +153,7 @@

      {% endfor %}

      - Request priors + {{ appLink({ text: "Request priors", href: "./request-priors", classes: "nhsuk-link--no-visited-state" } | openInModal) }}

      {% endset %} @@ -375,7 +375,6 @@

      {{ questionText }}

      - {# Image notes - moved above opinion section #} {% include "_includes/reading/image-warnings.njk" %} @@ -407,6 +406,15 @@

      {{ questionText }}

      } }) }} + {# Defer case option #} +
      +
      +

      + {{ appLink({ text: "Defer this case", href: "./defer-case", classes: "nhsuk-link--no-visited-state" } | openInModal) }} +

      +
      +
      + {% endblock %} {% block pageScripts %} diff --git a/app/views/reading/workflow/request-priors.html b/app/views/reading/workflow/request-priors.html index 0ff46aef..56ddfeb4 100644 --- a/app/views/reading/workflow/request-priors.html +++ b/app/views/reading/workflow/request-priors.html @@ -1,8 +1,9 @@ {# app/views/reading/workflow/request-priors.html #} -{% extends 'layout-reading.html' %} +{% extends parentLayout or 'layout-reading.html' %} {% set pageHeading = "Request prior images" %} +{% set formAction = './request-priors-answer' | urlWithReferrer(referrerChain) %} {% set back = { href: "./opinion", text: "Back" @@ -19,12 +20,10 @@
      -
      - -

      - {{ caption }} - {{ pageHeading }} -

      +

      + {{ caption }} + {{ pageHeading }} +

      This case will be put on hold while all available mammogram images for {{ participant | getFullName }} are sourced through the Image Exchange Portal (IEP). @@ -91,8 +90,6 @@

      text: "Confirm request and continue" }) }} - -

      diff --git a/app/views/settings.html b/app/views/settings.html index efd6c10f..16586d08 100755 --- a/app/views/settings.html +++ b/app/views/settings.html @@ -76,7 +76,7 @@

      Error

    • Modal forms: off
    • Compare page: off
    • Review pages off
    • -
    • Annotations mode: inline form (no image markers)
    • + Annotations mode: inline form (no image markers) From 94553eaa34d0abcee27e40e5751c7fe55cdf5036 Mon Sep 17 00:00:00 2001 From: Danny Chadburn Date: Fri, 12 Jun 2026 17:00:16 +0100 Subject: [PATCH 05/12] New mammogram appointment warning message (#328) Updated message regarding mammogram timing and removed unnecessary conditional checks. --- .../appointment-should-not-take-place.html | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 app/views/events/previous-mammograms/appointment-should-not-take-place.html diff --git a/app/views/events/previous-mammograms/appointment-should-not-take-place.html b/app/views/events/previous-mammograms/appointment-should-not-take-place.html new file mode 100644 index 00000000..8f1c660f --- /dev/null +++ b/app/views/events/previous-mammograms/appointment-should-not-take-place.html @@ -0,0 +1,66 @@ +{# app/views/events/previous-mammograms/appointment-should-not-begin.html #} + +{% extends parentLayout or 'layout-appointment.html' %} + +{% set previousMammogramCount = event.previousMammograms | length %} + +{% set pageHeading = "This appointment should not take place" %} + +{% set formAction = './save' | urlWithReferrer(referrerChain, query.scrollTo) %} + +{% block pageContent %} + + {% set previousMammograms = event.previousMammograms %} + + {% set unit = data.breastScreeningUnits | findById(clinic.breastScreeningUnitId) %} + +

      + + {{ participant | getFullName }} + + {{ pageHeading }} +

      + +

      + There is a mammogram on this participant's record from within the last 6 months. Breast x-rays should not be taken within 6 months of a previous mammogram. +

      + +{% set mammogramHistoryHtml %} + {% include "_includes/medical-information/mammogram-history.njk" %} +{% endset %} + + {{ radios({ + name: "event[appointmentStopped][needsReschedule]", + value: event.appointmentStopped.needsReschedule, + fieldset: { + legend: { + text: "Should the appointment be rescheduled?", + size: "m", + isPageHeading: false + } + }, + items: [ + { + value: "yes", + text: "Yes" + }, + { + value: "no-invite", + text: "No, invite to next routine appointment" + } + ] + } | populateErrors) }} + + {# Prevents redirect loop - signals to the save route that we've already shown this warning page #} + + +
      + {{ button({ + text: "Continue" + }) }} +
      + +

      + Proceed with this appointment +

      +{% endblock %} From e13f6662665a7e568e79226488e0d739547f7043 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Tue, 16 Jun 2026 10:32:10 +0100 Subject: [PATCH 06/12] Fix broken early compare journey (#333) --- app/assets/javascript/modal.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascript/modal.js b/app/assets/javascript/modal.js index 671e4119..355df9b4 100644 --- a/app/assets/javascript/modal.js +++ b/app/assets/javascript/modal.js @@ -194,12 +194,15 @@ class AppModal { // forgot 'parentLayout or'. Bail out to a direct navigation rather than // injecting the full site into the modal. if (this.isFullPage(html)) { + // Capture the destination before close() — close() resets _loadUrl to + // null, so reading it after would navigate to a literal "null" URL. + const dest = this._loadUrl console.warn( 'Modal: full page returned — falling back to direct navigation', - this._loadUrl + dest ) this.close() - window.location.href = this._loadUrl + window.location.href = dest return } From 441871be39142d9567fc3faa8ac96844eaf9527e Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Tue, 16 Jun 2026 12:43:29 +0100 Subject: [PATCH 07/12] Don't tie phone numbers to mobile and home (#334) --- app/lib/generators/participant-generator.js | 16 ++++++++-------- app/lib/utils/strings.js | 2 ++ app/routes/events.js | 11 +++++++++++ app/views/_includes/forms/contact-details.njk | 16 ++++++++-------- .../summary-lists/rows/phone-numbers.njk | 2 +- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/app/lib/generators/participant-generator.js b/app/lib/generators/participant-generator.js index 63d08361..c8c2c1be 100644 --- a/app/lib/generators/participant-generator.js +++ b/app/lib/generators/participant-generator.js @@ -103,20 +103,20 @@ const generatePhoneNumbers = () => { }) const result = { - mobilePhone: null, - homePhone: null + phone1: null, + phone2: null } switch (phoneConfig) { case 'mobile_only': - result.mobilePhone = generateUKMobileNumber() + result.phone1 = generateUKMobileNumber() break case 'both': - result.mobilePhone = generateUKMobileNumber() - result.homePhone = generateUKHomeNumber() + result.phone1 = generateUKMobileNumber() + result.phone2 = generateUKHomeNumber() break case 'home_only': - result.homePhone = generateUKHomeNumber() + result.phone2 = generateUKHomeNumber() break } @@ -216,8 +216,8 @@ const generateParticipant = ({ lastName: faker.person.lastName(), dateOfBirth: generateDateOfBirth(participantRiskLevel), address: generateBSUAppropriateAddress(assignedBSU), - mobilePhone: phoneNumbers.mobilePhone, - homePhone: phoneNumbers.homePhone, + phone1: phoneNumbers.phone1, + phone2: phoneNumbers.phone2, email: `${faker.internet.username().toLowerCase()}@example.com`, ethnicGroup: ethnicityData.ethnicGroup, ethnicBackground: ethnicityData.ethnicBackground diff --git a/app/lib/utils/strings.js b/app/lib/utils/strings.js index 5e58181c..f142468b 100644 --- a/app/lib/utils/strings.js +++ b/app/lib/utils/strings.js @@ -325,6 +325,8 @@ const formatPhoneNumber = (phoneNumber) => { if (!phoneNumber) return '' if (typeof phoneNumber !== 'string') return phoneNumber + phoneNumber = phoneNumber.replace(/\s/g, '') + if (phoneNumber.startsWith('07')) { return `${phoneNumber.slice(0, 5)} ${phoneNumber.slice(5)}` } diff --git a/app/routes/events.js b/app/routes/events.js index 9e59c800..d733ccd5 100644 --- a/app/routes/events.js +++ b/app/routes/events.js @@ -3353,6 +3353,17 @@ module.exports = (router) => { res.redirect(modalBreakout(returnUrl)) } ) + // Save participant data when contact details are updated from the participant tab. + // The contact-details form posts back to the participant tab URL via referrerChain, + // so we need this POST handler to persist the temp participant to the participants array. + router.post('/clinics/:clinicId/events/:eventId/participant', (req, res) => { + const { clinicId, eventId } = req.params + const data = req.session.data + saveTempParticipantToParticipant(data) + req.flash('success', 'Participant details updated') + res.redirect(`/clinics/${clinicId}/events/${eventId}/participant`) + }) + // General purpose dynamic template route for events // This should come after any more specific routes router.get( diff --git a/app/views/_includes/forms/contact-details.njk b/app/views/_includes/forms/contact-details.njk index e42d1b68..00a50037 100644 --- a/app/views/_includes/forms/contact-details.njk +++ b/app/views/_includes/forms/contact-details.njk @@ -74,24 +74,24 @@ {{ input({ label: { - text: "Mobile (optional)", + text: "Phone number 1 (optional)", _classes: "nhsuk-label--m" }, - value: participant.demographicInformation.mobilePhone, - id: "mobile-phone-number", - name: "participant[demographicInformation][mobilePhone]", + value: participant.demographicInformation.phone1, + id: "phone-number-1", + name: "participant[demographicInformation][phone1]", classes: "nhsuk-u-width-one-half" }) }} {{ input({ label: { - text: "Home (optional)", + text: "Phone number 2 (optional)", _classes: "nhsuk-label--m" }, - value: participant.demographicInformation.homePhone, - id: "home-phone-number", - name: "participant[demographicInformation][homePhone]", + value: participant.demographicInformation.phone2, + id: "phone-number-2", + name: "participant[demographicInformation][phone2]", classes: "nhsuk-u-width-one-half" }) }} diff --git a/app/views/_includes/summary-lists/rows/phone-numbers.njk b/app/views/_includes/summary-lists/rows/phone-numbers.njk index 345eebdd..9aee4346 100644 --- a/app/views/_includes/summary-lists/rows/phone-numbers.njk +++ b/app/views/_includes/summary-lists/rows/phone-numbers.njk @@ -1,6 +1,6 @@ {# /app/views/_includes/summary-lists/rows/phone-numbers.njk #} -{% set phoneNumbers = [participant.demographicInformation.mobilePhone, participant.demographicInformation.homePhone] | removeEmpty %} +{% set phoneNumbers = [participant.demographicInformation.phone1, participant.demographicInformation.phone2] | removeEmpty %} {% set phoneNumbersHtml %} {{ phoneNumbers | map("formatPhoneNumber") | join("
      ") | safe }} From 041ca5855f3f00bf4611f0b59a132e74df0653f3 Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Tue, 16 Jun 2026 14:19:48 +0100 Subject: [PATCH 08/12] Fix bug with annotation markers not showing (#335) --- app/assets/sass/components/_annotate-v2.scss | 1 + .../recall-for-assessment-details.html | 41 ++++++++++++++----- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/assets/sass/components/_annotate-v2.scss b/app/assets/sass/components/_annotate-v2.scss index 8ce421e0..94e2ea33 100644 --- a/app/assets/sass/components/_annotate-v2.scss +++ b/app/assets/sass/components/_annotate-v2.scss @@ -335,6 +335,7 @@ $ann-marker-shadow: // Cursor preview: yellow circle+plus that follows the mouse on image panels .app-ann-cursor-preview { position: absolute; + z-index: 4; // above zoom button (z-index: 3) and active markers (z-index: 2) width: $ann-marker-size; height: $ann-marker-size; border: $ann-marker-border-width solid $nhsuk-focus-colour; diff --git a/app/views/reading/workflow/recall-for-assessment-details.html b/app/views/reading/workflow/recall-for-assessment-details.html index 169ac52f..bcf2abde 100644 --- a/app/views/reading/workflow/recall-for-assessment-details.html +++ b/app/views/reading/workflow/recall-for-assessment-details.html @@ -254,9 +254,6 @@

      var side = nameMatch[1] var value = e.target.value - // Persist the breast assessment to session immediately - fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value)) - // Switch the active tab to match the selected side (tab-based modes) if (window._annotationInstance && window._annotationInstance.switchSide) { window._annotationInstance.switchSide(side) @@ -274,21 +271,43 @@

      } } - if (value !== 'abnormal') return + if (value !== 'abnormal') { + // Still persist the breast assessment for non-abnormal selections + fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value)) + return + } var countEl = document.querySelector('[data-annotation-count="' + side + '"]') var count = countEl ? parseInt(countEl.dataset.count || '0', 10) : 0 // In full tabbed mode, user clicks images directly — no auto-open - if (count === 0 && annotationsMode === 'with-images') return + if (count === 0 && annotationsMode === 'with-images') { + // Still persist the breast assessment to session + fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value)) + return + } if (count === 0) { - var url = './annotation/add?side=' + side - if (useModals && typeof window.openModal === 'function') { - window.openModal('app-form-modal', { loadUrl: url }) - } else { - window.location.href = url - } + // Wait for the save to complete before opening the modal, + // so the server has the breast side info in the session when rendering the annotation page + fetch('./save-breast-assessment?side=' + side + '&value=' + encodeURIComponent(value)) + .then(() => { + var url = './annotation/add?side=' + side + if (useModals && typeof window.openModal === 'function') { + window.openModal('app-form-modal', { loadUrl: url }) + } else { + window.location.href = url + } + }) + .catch(() => { + // Graceful degradation: open modal even if save fails + var url = './annotation/add?side=' + side + if (useModals && typeof window.openModal === 'function') { + window.openModal('app-form-modal', { loadUrl: url }) + } else { + window.location.href = url + } + }) } }) })() From b9ce60d40bf34e9dc83242ab472da0afe7ebb352 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:04:51 +0100 Subject: [PATCH 09/12] Bump esbuild from 0.28.0 to 0.28.1 (#332) Bumps [esbuild](https://github.com/evanw/esbuild) from 0.28.0 to 0.28.1. - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md) - [Commits](https://github.com/evanw/esbuild/compare/v0.28.0...v0.28.1) --- updated-dependencies: - dependency-name: esbuild dependency-version: 0.28.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 214 +++++++++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/package-lock.json b/package-lock.json index 206023e7..a1522539 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,9 +45,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -61,9 +61,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -77,9 +77,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -93,9 +93,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -109,9 +109,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -125,9 +125,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -141,9 +141,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -157,9 +157,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -173,9 +173,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -189,9 +189,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -205,9 +205,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -221,9 +221,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -237,9 +237,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -253,9 +253,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -269,9 +269,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -285,9 +285,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -301,9 +301,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -317,9 +317,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -333,9 +333,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -349,9 +349,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -365,9 +365,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -381,9 +381,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -397,9 +397,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -413,9 +413,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -429,9 +429,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -445,9 +445,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -2577,9 +2577,9 @@ } }, "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "hasInstallScript": true, "license": "MIT", "peer": true, @@ -2590,32 +2590,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/esbuild-clean-plugin": { From 06f46144ee4c56f65b764c8cb7c87eda93b7d80d Mon Sep 17 00:00:00 2001 From: Ed Horsford Date: Wed, 17 Jun 2026 15:53:58 +0100 Subject: [PATCH 10/12] Update symptoms form (#338) * Change not sure to not known * Swap symptom investigation for checkbox * Rework symptoms questions --- .../medical-information/symptoms-generator.js | 8 +- app/routes/events.js | 31 +++-- .../medical-information/symptoms/summary.njk | 25 ++-- .../medical-information/symptoms/details.html | 110 ++++++++---------- 4 files changed, 81 insertions(+), 93 deletions(-) diff --git a/app/lib/generators/medical-information/symptoms-generator.js b/app/lib/generators/medical-information/symptoms-generator.js index 24b3b83f..4e79f84c 100644 --- a/app/lib/generators/medical-information/symptoms-generator.js +++ b/app/lib/generators/medical-information/symptoms-generator.js @@ -199,7 +199,7 @@ const generateSymptom = (options = {}) => { const dateTypeWeights = { ...Object.fromEntries(DATE_RANGE_OPTIONS.map((range) => [range, 0.1])), dateKnown: 0.3, - notSure: 0.1 + notKnown: 0.1 } // Generate basic symptom data matching form structure @@ -332,16 +332,16 @@ const generateSymptom = (options = {}) => { } } - // 20% chance of additional info + // 20% chance of symptom notes if (Math.random() < 0.2) { - const additionalInfoOptions = [ + const symptomNotesOptions = [ 'Noticed during self-examination', 'Partner noticed the change', 'Gets worse during certain times of month', 'No family history of breast problems', 'Concerned as mother had similar symptoms' ] - symptom.additionalInfo = faker.helpers.arrayElement(additionalInfoOptions) + symptom.symptomNotes = faker.helpers.arrayElement(symptomNotesOptions) } return symptom diff --git a/app/routes/events.js b/app/routes/events.js index d733ccd5..9ea633be 100644 --- a/app/routes/events.js +++ b/app/routes/events.js @@ -1142,17 +1142,12 @@ module.exports = (router) => { }) } - // Validate whether the symptom has been investigated (required) - if (!data.event?.symptomTemp?.hasBeenInvestigated) { - validationErrors.push({ - name: 'event[symptomTemp][hasBeenInvestigated]', - text: 'Select whether this has been investigated', - href: '#hasBeenInvestigated' - }) - } else if ( - data.event.symptomTemp.hasBeenInvestigated === 'yes' && - !data.event.symptomTemp.investigatedDescription - ) { + // Validate investigation details if the checkbox is checked + const hasBeenInvestigated = data.event?.symptomTemp?.hasBeenInvestigated + const isInvestigated = Array.isArray(hasBeenInvestigated) + ? hasBeenInvestigated.includes('yes') + : hasBeenInvestigated === 'yes' + if (isInvestigated && !data.event?.symptomTemp?.investigatedDescription) { validationErrors.push({ name: 'event[symptomTemp][investigatedDescription]', text: 'Provide details of the investigation', @@ -1221,8 +1216,7 @@ module.exports = (router) => { id: symptomTemp.id || generateId(), type: symptomType, dateType: symptomTemp.dateType, - hasBeenInvestigated: symptomTemp.hasBeenInvestigated, - additionalInfo: symptomTemp.additionalInfo + symptomNotes: symptomTemp.symptomNotes } // For new symptoms, add the creation timestamp @@ -1240,8 +1234,13 @@ module.exports = (router) => { } } - // Add investigation details if investigated - if (symptomTemp.hasBeenInvestigated === 'yes') { + // Normalise checkbox value and add investigation details if checked + const savedHasBeenInvestigated = symptomTemp.hasBeenInvestigated + const savedIsInvestigated = Array.isArray(savedHasBeenInvestigated) + ? savedHasBeenInvestigated.includes('yes') + : savedHasBeenInvestigated === 'yes' + symptom.hasBeenInvestigated = savedIsInvestigated ? 'yes' : 'no' + if (savedIsInvestigated) { symptom.investigatedDescription = symptomTemp.investigatedDescription } @@ -1258,7 +1257,7 @@ module.exports = (router) => { ].includes(symptomTemp.dateType) ) { symptom.approximateDuration = symptomTemp.dateType - } else if (symptomTemp.dateType === 'notSure') { + } else if (symptomTemp.dateType === 'notKnown') { delete symptom.approximateDuration } diff --git a/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk b/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk index 6b4ca60a..fe32d5b4 100644 --- a/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk +++ b/app/views/_includes/summary-lists/medical-information/symptoms/summary.njk @@ -86,34 +86,35 @@ {{ symptom.dateStarted | formatMonthYear }} ({{ symptom.dateStarted | formatRelativeDate }}) {% elseif symptom.approximateDuration %} {{ symptom.approximateDuration }} ago - {% elseif symptom.dateType == 'notSure' %} - not sure + {% elseif symptom.dateType == 'notKnown' %} + not known {% else %} not provided {% endif %} {% endset %} {% set valueLines = valueLines | push(startText) %} - {# Stop date if applicable #} + {# Additional symptom information #} {% if symptom.isIntermittent %} {% set valueLines = valueLines | push("Symptom is intermittent") %} {% endif %} - {# Stop date if applicable #} {% if symptom.hasStopped and symptom.approximateDateStopped %} - {% set valueLines = valueLines | push("Stopped: " + symptom.approximateDateStopped) %} + {% set valueLines = valueLines | push("Recently resolved (" + symptom.approximateDateStopped + ")") %} {% endif %} {# Investigation status #} - {% if symptom.hasBeenInvestigated == "yes" and symptom.investigatedDescription %} - {% set valueLines = valueLines | push("Investigated: " + symptom.investigatedDescription) %} - {% elseif symptom.hasBeenInvestigated == "no" %} - {% set valueLines = valueLines | push("Not investigated") %} + {% if symptom.hasBeenInvestigated == "yes" %} + {% if symptom.investigatedDescription %} + {% set valueLines = valueLines | push("Previously investigated: " + symptom.investigatedDescription) %} + {% else %} + {% set valueLines = valueLines | push("Previously investigated") %} + {% endif %} {% endif %} - {# Additional info #} - {% if symptom.additionalInfo %} - {% set valueLines = valueLines | push("Additional info: " + symptom.additionalInfo) %} + {# Symptom notes #} + {% if symptom.symptomNotes %} + {% set valueLines = valueLines | push("Notes: " + symptom.symptomNotes) %} {% endif %} {# Join all value lines with line breaks #} diff --git a/app/views/events/medical-information/symptoms/details.html b/app/views/events/medical-information/symptoms/details.html index eda86e94..771c23ee 100644 --- a/app/views/events/medical-information/symptoms/details.html +++ b/app/views/events/medical-information/symptoms/details.html @@ -467,13 +467,11 @@

      }) %} {% set dateRadioItems = dateRadioItems | push({ - value: "notSure", - text: "Not sure" + value: "notKnown", + text: "Not known" }) %} - - - {# Radios for when were they taken - choices 'Date known' and 'Enter approximate date' and 'Not sure' #} + {# Radios for when were they taken - choices 'Date known' and 'Enter approximate date' and 'Not known' #} {{ radios({ idPrefix: "dateType", name: "event[symptomTemp][dateType]", @@ -503,18 +501,38 @@

      } | populateErrors) }} {% endset %} - {# TODO: don't use br for spacing! #} -
      + {% set investigatedDescriptionHtml %} + {{ textarea({ + id: "investigatedDescription", + name: "event[symptomTemp][investigatedDescription]", + label: { + text: "Provide details" + }, + hint: { + text: "Include where, when and the outcome" + }, + value: event.symptomTemp.investigatedDescription + } | populateErrors) }} + {% endset %} - + {% call fieldset({ + legend: { + text: "Additional symptom information", + size: "m", + isPageHeading: false + } + }) %} {{ checkboxes({ idPrefix: "isIntermittent", name: "event[symptomTemp][isIntermittent]", + formGroup: { + classes: "nhsuk-u-margin-bottom-3" + }, items: [ { value: "yes", - text: "The symptom is intermittent", + text: "Intermittent", checked: true if event.symptomTemp.isIntermittent else false } ] @@ -523,10 +541,13 @@

      {{ checkboxes({ idPrefix: "hasStopped", name: "event[symptomTemp][hasStopped]", + formGroup: { + classes: "nhsuk-u-margin-bottom-3" + }, items: [ { value: "yes", - text: "The symptom has recently resolved", + text: "Recently resolved", checked: true if event.symptomTemp.hasStopped else false, conditional: { html: stymptomStoppedHtml @@ -535,42 +556,22 @@

      ] }) }} - {{ radios({ - idPrefix: "hasBeenInvestigated", - name: "event[symptomTemp][hasBeenInvestigated]", - value: event.symptomTemp.hasBeenInvestigated, - fieldset: { - legend: { - text: "Has this been investigated?", - size: "m", - isPageHeading: false - } - }, - items: [ - { - value: "yes", - text: "Yes", - conditional: { - html: textarea({ - id: "investigatedDescription", - name: "event[symptomTemp][investigatedDescription]", - label: { - text: "Provide details" - }, - hint: { - text: "Include where, when and the outcome" - }, - value: event.symptomTemp.investigatedDescription, - _classes: "nhsuk-u-width-two-thirds" - } | populateErrors) + {{ checkboxes({ + idPrefix: "hasBeenInvestigated", + name: "event[symptomTemp][hasBeenInvestigated]", + values: event.symptomTemp.hasBeenInvestigated, + items: [ + { + value: "yes", + text: "Investigated by a medical professional", + conditional: { + html: investigatedDescriptionHtml + } } - }, - { - value: "no", - text: "No" - } - ] - } | populateErrors) }} + ] + }) }} + + {% endcall %} {# Only show if not significant by default #} {% if not symptomType.isSignificantByDefault %} @@ -611,29 +612,16 @@

      ] } | populateErrors) }} - {# {{ checkboxes({ - idPrefix: "isSignificant", - name: "event[symptomTemp][isSignificant]", - items: [ - { - value: "yes", - text: "Highlight this symptom to image readers", - checked: true if event.symptomTemp.isSignificant else false - } - ] - }) }} #} {% endif %} - - {{ textarea({ - name: "event[symptomTemp][additionalInfo]", + name: "event[symptomTemp][symptomNotes]", label: { - text: "Additional info (optional)", + text: "Symptom notes (optional)", size: "m" }, rows: 4, - value: event.symptomTemp.additionalInfo + value: event.symptomTemp.symptomNotes }) }}
      From 419689a51345455b3f7c7ea9bfb91d1411b29a94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:57:20 +0100 Subject: [PATCH 11/12] Bump form-data from 4.0.5 to 4.0.6 (#337) Bumps [form-data](https://github.com/form-data/form-data) from 4.0.5 to 4.0.6. - [Release notes](https://github.com/form-data/form-data/releases) - [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md) - [Commits](https://github.com/form-data/form-data/compare/v4.0.5...v4.0.6) --- updated-dependencies: - dependency-name: form-data dependency-version: 4.0.6 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1522539..8db5cbef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2887,16 +2887,16 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" From b37defa1074407e067f8ad7230cc9ec03425c249 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:59:25 +0100 Subject: [PATCH 12/12] Bump ws, engine.io-client, engine.io and socket.io-adapter (#336) Bumps [ws](https://github.com/websockets/ws), [engine.io-client](https://github.com/socketio/socket.io), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together. Updates `ws` from 8.20.1 to 8.21.0 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.20.1...8.21.0) Updates `engine.io-client` from 6.6.5 to 6.6.6 - [Release notes](https://github.com/socketio/socket.io/releases) - [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.5...engine.io-client@6.6.6) Updates `engine.io` from 6.6.8 to 6.6.9 - [Release notes](https://github.com/socketio/socket.io/releases) - [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.8...engine.io@6.6.9) Updates `socket.io-adapter` from 2.5.7 to 2.5.8 - [Release notes](https://github.com/socketio/socket.io/releases) - [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.7...socket.io-adapter@2.5.8) --- updated-dependencies: - dependency-name: ws dependency-version: 8.21.0 dependency-type: indirect - dependency-name: engine.io-client dependency-version: 6.6.6 dependency-type: indirect - dependency-name: engine.io dependency-version: 6.6.9 dependency-type: indirect - dependency-name: socket.io-adapter dependency-version: 2.5.8 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8db5cbef..d515156a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2434,9 +2434,9 @@ } }, "node_modules/engine.io": { - "version": "6.6.8", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz", - "integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==", + "version": "6.6.9", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz", + "integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==", "license": "MIT", "dependencies": { "@types/cors": "^2.8.12", @@ -2448,22 +2448,22 @@ "cors": "~2.8.5", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.20.1" + "ws": "~8.21.0" }, "engines": { "node": ">=10.2.0" } }, "node_modules/engine.io-client": { - "version": "6.6.5", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.5.tgz", - "integrity": "sha512-QCwxUDULPlXv8F6tqMMKx5dNkTe6OaBYRMPYeXKBlyOoKvAmE0ac6pW7fFhSscJ/5SI7666/U/B+MElbsrJlIg==", + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.6.tgz", + "integrity": "sha512-iY6QdftLQ9pyiPoX082bpf/u1UewnOaJrtJIF9T0++QB34lZrj0uP+Q/bj8AlUsAxqhnkTV2BS8SBZSxOmoV5Q==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.20.1", + "ws": "~8.21.0", "xmlhttprequest-ssl": "~2.1.1" } }, @@ -5532,13 +5532,13 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz", - "integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz", + "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==", "license": "MIT", "dependencies": { "debug": "~4.4.1", - "ws": "~8.20.1" + "ws": "~8.21.0" } }, "node_modules/socket.io-client": { @@ -6040,9 +6040,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0"