diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4faf795d13..34f3f7a621 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -223,28 +223,16 @@ Follow these steps to set up the OWASP Nest application: 1. **Create Environment Files**: - - Create a local environment file in the `backend` directory: + - Copy the contents from the template file into your new backend local environment file: ```bash - touch backend/.env + cp backend/.env.example backend/.env ``` - - Copy the contents from the template file into your new local environment file: + - Copy the contents from the template file into your new frontend local environment file: ```bash - cat backend/.env.example > backend/.env - ``` - - - Create a local environment file in the `frontend` directory: - - ```bash - touch frontend/.env - ``` - - - Copy the contents from the template file into your new local environment file: - - ```bash - cat frontend/.env.example > frontend/.env + cp frontend/.env.example frontend/.env ``` Ensure that all `.env` files are saved in **UTF-8 format without BOM (Byte Order Mark)**. This is crucial to prevent "Unexpected character" errors during application execution or Docker image building. @@ -262,7 +250,8 @@ Ensure that all `.env` files are saved in **UTF-8 format without BOM (Byte Order 1. **Set Up Algolia**: - Go to [Algolia](https://www.algolia.com/) and create a free account. - - After creating an account, create an Algolia app. + - An Algolia app is automatically created for you when you sign up. + - During the sign up process, you may be asked to import data. You can skip this step. - Update your `backend/.env` file with the following keys from your Algolia app (use **write** API key for backend): ```plaintext @@ -270,7 +259,7 @@ Ensure that all `.env` files are saved in **UTF-8 format without BOM (Byte Order DJANGO_ALGOLIA_WRITE_API_KEY= ``` - - Ensure that your API key has index write permissions. You can ignore any onboarding wizard instructions provided by Algolia. + - Note: The default write API key should have index write permissions (addObject permission). If you do not use the default write API key, ensure that your API key has this permission. - If you encounter any issues, you can refer directly to Algolia's [documentation](https://www.algolia.com/doc/guides/getting-started/quick-start/) 1. **Run the Application**: diff --git a/backend/apps/api/rest/v0/snapshot.py b/backend/apps/api/rest/v0/snapshot.py index 0825f01107..50ef169d6c 100644 --- a/backend/apps/api/rest/v0/snapshot.py +++ b/backend/apps/api/rest/v0/snapshot.py @@ -23,6 +23,8 @@ from apps.owasp.models.project import Project as ProjectModel from apps.owasp.models.snapshot import Snapshot as SnapshotModel +ORDERING_FIELD_DESCRIPTION = "Ordering field" + router = RouterPaginated(tags=["Community"]) @@ -114,7 +116,7 @@ def list_snapshots( ] | None = Query( None, - description="Ordering field", + description=ORDERING_FIELD_DESCRIPTION, ), ) -> list[Snapshot]: """Get all snapshots.""" @@ -160,7 +162,7 @@ def list_snapshot_chapters( snapshot_id: str = Path(example="2025-02"), ordering: Literal["created_at", "-created_at", "updated_at", "-updated_at"] | None = Query( None, - description="Ordering field", + description=ORDERING_FIELD_DESCRIPTION, ), ) -> list[Chapter]: """Get new chapters in snapshot.""" @@ -185,7 +187,7 @@ def list_snapshot_issues( snapshot_id: str = Path(example="2025-02"), ordering: Literal["created_at", "-created_at", "updated_at", "-updated_at"] | None = Query( None, - description="Ordering field", + description=ORDERING_FIELD_DESCRIPTION, ), ) -> list[SnapshotIssue]: """Get new issues in snapshot.""" @@ -212,7 +214,7 @@ def list_snapshot_members( snapshot_id: str = Path(example="2025-02"), ordering: Literal["created_at", "-created_at", "updated_at", "-updated_at"] | None = Query( None, - description="Ordering field", + description=ORDERING_FIELD_DESCRIPTION, ), ) -> list[Member]: """Get new members in snapshot.""" @@ -237,7 +239,7 @@ def list_snapshot_projects( snapshot_id: str = Path(example="2025-02"), ordering: Literal["created_at", "-created_at", "updated_at", "-updated_at"] | None = Query( None, - description="Ordering field", + description=ORDERING_FIELD_DESCRIPTION, ), ) -> list[Project]: """Get new projects in snapshot.""" @@ -262,7 +264,7 @@ def list_snapshot_releases( snapshot_id: str = Path(example="2025-02"), ordering: Literal["created_at", "-created_at", "published_at", "-published_at"] | None = Query( None, - description="Ordering field", + description=ORDERING_FIELD_DESCRIPTION, ), ) -> list[SnapshotRelease]: """Get new releases in snapshot.""" diff --git a/backend/apps/owasp/models/common.py b/backend/apps/owasp/models/common.py index ef21936943..d30cc5cc6f 100644 --- a/backend/apps/owasp/models/common.py +++ b/backend/apps/owasp/models/common.py @@ -239,7 +239,7 @@ def get_metadata(self): """Get entity metadata.""" try: yaml_content = re.search( - r"^---\s*([\s\S]*?)\s*---", + r"^---\s*(.*?)\s*---", get_repository_file_content(self.index_md_url), re.DOTALL, ) diff --git a/backend/poetry.lock b/backend/poetry.lock index 4473d2064a..4d93ced2db 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -275,18 +275,18 @@ files = [ [[package]] name = "boto3" -version = "1.42.17" +version = "1.42.19" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.42.17-py3-none-any.whl", hash = "sha256:e0ee40f7102712452f6776af891c8f49b5ae9133bdaf22711d6f4a78963c2614"}, - {file = "boto3-1.42.17.tar.gz", hash = "sha256:8a2e345e96d5ceba755c55539c93f99705f403fbfdeef2e838eabdc56750828b"}, + {file = "boto3-1.42.19-py3-none-any.whl", hash = "sha256:c55b8b303c64931272536813a476f130b90ea7041d7b79c154d89cf1c18256b4"}, + {file = "boto3-1.42.19.tar.gz", hash = "sha256:5933696a28bf8eb62fc54e4de5583f78a0efef59c8164ee1850436aa22f53aa7"}, ] [package.dependencies] -botocore = ">=1.42.17,<1.43.0" +botocore = ">=1.42.19,<1.43.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.16.0,<0.17.0" @@ -295,14 +295,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.42.17" +version = "1.42.19" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.42.17-py3-none-any.whl", hash = "sha256:a832e4c04e63141221480967e9e511363aa54d24c405935fccb913a18583c96b"}, - {file = "botocore-1.42.17.tar.gz", hash = "sha256:d73fe22c8e1497e4d59ff7dc68eb05afac68a4a6457656811562285d6132bc04"}, + {file = "botocore-1.42.19-py3-none-any.whl", hash = "sha256:30c276e0a96d822826d74e961089b9af16b274ac7ddcf7dcf6440bc90d856d88"}, + {file = "botocore-1.42.19.tar.gz", hash = "sha256:8d38f30de983720303e95951380a2c9ac515159636ee6b5ba4227d65f14551a4"}, ] [package.dependencies] @@ -1912,14 +1912,14 @@ orjson = ">=3.10.1" [[package]] name = "langsmith" -version = "0.5.1" +version = "0.5.2" description = "Client library to connect to the LangSmith Observability and Evaluation Platform." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "langsmith-0.5.1-py3-none-any.whl", hash = "sha256:70aa2a4c75add3f723c3bbac80dbb8adc575077834d3a733ee1ec133206ff351"}, - {file = "langsmith-0.5.1.tar.gz", hash = "sha256:6a10b38cb4ce58941b7f1dbdf41a461868605dd0162bf05d17690f2e4b6e50e7"}, + {file = "langsmith-0.5.2-py3-none-any.whl", hash = "sha256:42f8b853a18dd4d5f7fa38c8ff29e38da065a727022da410d91b3e13819aacc1"}, + {file = "langsmith-0.5.2.tar.gz", hash = "sha256:a6186d555ba59732b1b10e2ba6fe34ee0b3c1bf3a7fb8d7be0dec367ac3b75f1"}, ] [package.dependencies] @@ -3039,10 +3039,8 @@ files = [ {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c47676e5b485393f069b4d7a811267d3168ce46f988fa602658b8bb901e9e64d"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a28d8c01a7b27a1e3265b11250ba7557e5f72b5ee9e5f3a2fa8d2949c29bf5d2"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f3f2732cf504a1aa9e9609d02f79bea1067d99edf844ab92c247bbca143303b"}, - {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:865f9945ed1b3950d968ec4690ce68c55019d79e4497366d36e090327ce7db14"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91537a8df2bde69b1c1db01d6d944c831ca793952e4f57892600e96cee95f2cd"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dca1f356a67ecb68c81a7bc7809f1569ad9e152ce7fd02c2f2036862ca9f66b"}, - {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0da4de5c1ac69d94ed4364b6cbe7190c1a70d325f112ba783d83f8440285f152"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37d8412565a7267f7d79e29ab66876e55cb5e8e7b3bbf94f8206f6795f8f7e7e"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:c665f01ec8ab273a61c62beeb8cce3014c214429ced8a308ca1fc410ecac3a39"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0e8480afd62362d0a6a27dd09e4ca2def6fa50ed3a4e7c09165266106b2ffa10"}, @@ -3050,10 +3048,8 @@ files = [ {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e164359396576a3cc701ba8af4751ae68a07235d7a380c631184a611220d9a4"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d57c9c387660b8893093459738b6abddbb30a7eab058b77b0d0d1c7d521ddfd7"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2c226ef95eb2250974bf6fa7a842082b31f68385c4f3268370e3f3870e7859ee"}, - {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a311f1edc9967723d3511ea7d2708e2c3592e3405677bf53d5c7246753591fbb"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ebb415404821b6d1c47353ebe9c8645967a5235e6d88f914147e7fd411419e6f"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f07c9c4a5093258a03b28fab9b4f151aa376989e7f35f855088234e656ee6a94"}, - {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:00ce1830d971f43b667abe4a56e42c1e2d594b32da4802e44a73bacacb25535f"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cffe9d7697ae7456649617e8bb8d7a45afb71cd13f7ab22af3e5c61f04840908"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:304fd7b7f97eef30e91b8f7e720b3db75fee010b520e434ea35ed1ff22501d03"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be9b840ac0525a283a96b556616f5b4820e0526addb8dcf6525a0fa162730be4"}, @@ -3061,10 +3057,8 @@ files = [ {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ab8905b5dcb05bf3fb22e0cf90e10f469563486ffb6a96569e51f897c750a76a"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf940cd7e7fec19181fdbc29d76911741153d51cab52e5c21165f3262125685e"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa0f693d3c68ae925966f0b14b8edda71696608039f4ed61b1fe9ffa468d16db"}, - {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a1cf393f1cdaf6a9b57c0a719a1068ba1069f022a59b8b1fe44b006745b59757"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7a6beb4beaa62f88592ccc65df20328029d721db309cb3250b0aae0fa146c3"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:31b32c457a6025e74d233957cc9736742ac5a6cb196c6b68499f6bb51390bd6a"}, - {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:edcb3aeb11cb4bf13a2af3c53a15b3d612edeb6409047ea0b5d6a21a9d744b34"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b6d93d7c0b61a1dd6197d208ab613eb7dcfdcca0a49c42ceb082257991de9d"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:b33fabeb1fde21180479b2d4667e994de7bbf0eec22832ba5d9b5e4cf65b6c6d"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8fb3db325435d34235b044b199e56cdf9ff41223a4b9752e8576465170bb38c"}, @@ -3072,10 +3066,8 @@ files = [ {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c55b385daa2f92cb64b12ec4536c66954ac53654c7f15a203578da4e78105c0"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c0377174bf1dd416993d16edc15357f6eb17ac998244cca19bc67cdc0e2e5766"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6ff3335ce08c75afaed19e08699e8aacf95d4a260b495a4a8545244fe2ceb3"}, - {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84011ba3109e06ac412f95399b704d3d6950e386b7994475b231cf61eec2fc1f"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba34475ceb08cccbdd98f6b46916917ae6eeb92b5ae111df10b544c3a4621dc4"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b31e90fdd0f968c2de3b26ab014314fe814225b6c324f770952f7d38abf17e3c"}, - {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d526864e0f67f74937a8fce859bd56c979f5e2ec57ca7c627f5f1071ef7fee60"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04195548662fa544626c8ea0f06561eb6203f1984ba5b4562764fbeb4c3d14b1"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:efff12b432179443f54e230fdf60de1f6cc726b6c832db8701227d089310e8aa"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:92e3b669236327083a2e33ccfa0d320dd01b9803b3e14dd986a4fc54aa00f4e1"}, @@ -3083,10 +3075,8 @@ files = [ {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b52a3f9bb540a3e4ec0f6ba6d31339727b2950c9772850d6545b7eae0b9d7c5"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:db4fd476874ccfdbb630a54426964959e58da4c61c9feba73e6094d51303d7d8"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47f212c1d3be608a12937cc131bd85502954398aaa1320cb4c14421a0ffccf4c"}, - {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e35b7abae2b0adab776add56111df1735ccc71406e56203515e228a8dc07089f"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fcf21be3ce5f5659daefd2b3b3b6e4727b028221ddc94e6c1523425579664747"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9bd81e64e8de111237737b29d68039b9c813bdf520156af36d26819c9a979e5f"}, - {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:32770a4d666fbdafab017086655bcddab791d7cb260a16679cc5a7338b64343b"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3cb3a676873d7506825221045bd70e0427c905b9c8ee8d6acd70cfcbd6e576d"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:4012c9c954dfaccd28f94e84ab9f94e12df76b4afb22331b1f0d3154893a6316"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20e7fb94e20b03dcc783f76c0865f9da39559dcc0c28dd1a3fce0d01902a6b9c"}, @@ -3094,10 +3084,8 @@ files = [ {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9d3a9edcfbe77a3ed4bc72836d466dfce4174beb79eda79ea155cc77237ed9e8"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:44fc5c2b8fa871ce7f0023f619f1349a0aa03a0857f2c96fbc01c657dcbbdb49"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9c55460033867b4622cda1b6872edf445809535144152e5d14941ef591980edf"}, - {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2d11098a83cca92deaeaed3d58cfd150d49b3b06ee0d0852be466bf87596899e"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:691c807d94aecfbc76a14e1408847d59ff5b5906a04a23e12a89007672b9e819"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b81627b691f29c4c30a8f322546ad039c40c328373b11dff7490a3e1b517855"}, - {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:b637d6d941209e8d96a072d7977238eea128046effbf37d1d8b2c0764750017d"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:41360b01c140c2a03d346cec3280cf8a71aa07d94f3b1509fa0161c366af66b4"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:875039274f8a2361e5207857899706da840768e2a775bf8c65e82f60b197df02"}, ] @@ -3352,39 +3340,36 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pynacl" -version = "1.6.1" +version = "1.6.2" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "pynacl-1.6.1-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:7d7c09749450c385301a3c20dca967a525152ae4608c0a096fe8464bfc3df93d"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc734c1696ffd49b40f7c1779c89ba908157c57345cf626be2e0719488a076d3"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3cd787ec1f5c155dc8ecf39b1333cfef41415dc96d392f1ce288b4fe970df489"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b35d93ab2df03ecb3aa506be0d3c73609a51449ae0855c2e89c7ed44abde40b"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dece79aecbb8f4640a1adbb81e4aa3bfb0e98e99834884a80eb3f33c7c30e708"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c2228054f04bf32d558fb89bb99f163a8197d5a9bf4efa13069a7fa8d4b93fc3"}, - {file = "pynacl-1.6.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:2b12f1b97346f177affcdfdc78875ff42637cb40dcf79484a97dae3448083a78"}, - {file = "pynacl-1.6.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e735c3a1bdfde3834503baf1a6d74d4a143920281cb724ba29fb84c9f49b9c48"}, - {file = "pynacl-1.6.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3384a454adf5d716a9fadcb5eb2e3e72cd49302d1374a60edc531c9957a9b014"}, - {file = "pynacl-1.6.1-cp314-cp314t-win32.whl", hash = "sha256:d8615ee34d01c8e0ab3f302dcdd7b32e2bcf698ba5f4809e7cc407c8cdea7717"}, - {file = "pynacl-1.6.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5f5b35c1a266f8a9ad22525049280a600b19edd1f785bccd01ae838437dcf935"}, - {file = "pynacl-1.6.1-cp314-cp314t-win_arm64.whl", hash = "sha256:d984c91fe3494793b2a1fb1e91429539c6c28e9ec8209d26d25041ec599ccf63"}, - {file = "pynacl-1.6.1-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:a6f9fd6d6639b1e81115c7f8ff16b8dedba1e8098d2756275d63d208b0e32021"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e49a3f3d0da9f79c1bec2aa013261ab9fa651c7da045d376bd306cf7c1792993"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7713f8977b5d25f54a811ec9efa2738ac592e846dd6e8a4d3f7578346a841078"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a3becafc1ee2e5ea7f9abc642f56b82dcf5be69b961e782a96ea52b55d8a9fc"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ce50d19f1566c391fedc8dc2f2f5be265ae214112ebe55315e41d1f36a7f0a9"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:543f869140f67d42b9b8d47f922552d7a967e6c116aad028c9bfc5f3f3b3a7b7"}, - {file = "pynacl-1.6.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a2bb472458c7ca959aeeff8401b8efef329b0fc44a89d3775cffe8fad3398ad8"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3206fa98737fdc66d59b8782cecc3d37d30aeec4593d1c8c145825a345bba0f0"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:53543b4f3d8acb344f75fd4d49f75e6572fce139f4bfb4815a9282296ff9f4c0"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:319de653ef84c4f04e045eb250e6101d23132372b0a61a7acf91bac0fda8e58c"}, - {file = "pynacl-1.6.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:262a8de6bba4aee8a66f5edf62c214b06647461c9b6b641f8cd0cb1e3b3196fe"}, - {file = "pynacl-1.6.1-cp38-abi3-win32.whl", hash = "sha256:9fd1a4eb03caf8a2fe27b515a998d26923adb9ddb68db78e35ca2875a3830dde"}, - {file = "pynacl-1.6.1-cp38-abi3-win_amd64.whl", hash = "sha256:a569a4069a7855f963940040f35e87d8bc084cb2d6347428d5ad20550a0a1a21"}, - {file = "pynacl-1.6.1-cp38-abi3-win_arm64.whl", hash = "sha256:5953e8b8cfadb10889a6e7bd0f53041a745d1b3d30111386a1bb37af171e6daf"}, - {file = "pynacl-1.6.1.tar.gz", hash = "sha256:8d361dac0309f2b6ad33b349a56cd163c98430d409fa503b10b70b3ad66eaa1d"}, + {file = "pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88"}, + {file = "pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444"}, + {file = "pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b"}, + {file = "pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590"}, + {file = "pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2"}, + {file = "pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130"}, + {file = "pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e"}, + {file = "pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577"}, + {file = "pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa"}, + {file = "pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0"}, + {file = "pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c"}, ] [package.dependencies] @@ -4264,14 +4249,12 @@ optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "sqlalchemy-2.0.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85"}, {file = "sqlalchemy-2.0.45-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4"}, {file = "sqlalchemy-2.0.45-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0"}, {file = "sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0"}, {file = "sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826"}, {file = "sqlalchemy-2.0.45-cp310-cp310-win32.whl", hash = "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a"}, {file = "sqlalchemy-2.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7"}, - {file = "sqlalchemy-2.0.45-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e90a344c644a4fa871eb01809c32096487928bd2038bf10f3e4515cb688cc56"}, {file = "sqlalchemy-2.0.45-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8c8b41b97fba5f62349aa285654230296829672fc9939cd7f35aab246d1c08b"}, {file = "sqlalchemy-2.0.45-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:12c694ed6468333a090d2f60950e4250b928f457e4962389553d6ba5fe9951ac"}, {file = "sqlalchemy-2.0.45-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f7d27a1d977a1cfef38a0e2e1ca86f09c4212666ce34e6ae542f3ed0a33bc606"}, @@ -4300,14 +4283,12 @@ files = [ {file = "sqlalchemy-2.0.45-cp314-cp314-win_amd64.whl", hash = "sha256:4748601c8ea959e37e03d13dcda4a44837afcd1b21338e637f7c935b8da06177"}, {file = "sqlalchemy-2.0.45-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd337d3526ec5298f67d6a30bbbe4ed7e5e68862f0bf6dd21d289f8d37b7d60b"}, {file = "sqlalchemy-2.0.45-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9a62b446b7d86a3909abbcd1cd3cc550a832f99c2bc37c5b22e1925438b9367b"}, - {file = "sqlalchemy-2.0.45-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5964f832431b7cdfaaa22a660b4c7eb1dfcd6ed41375f67fd3e3440fd95cb3cc"}, {file = "sqlalchemy-2.0.45-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee580ab50e748208754ae8980cec79ec205983d8cf8b3f7c39067f3d9f2c8e22"}, {file = "sqlalchemy-2.0.45-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13e27397a7810163440c6bfed6b3fe46f1bfb2486eb540315a819abd2c004128"}, {file = "sqlalchemy-2.0.45-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ed3635353e55d28e7f4a95c8eda98a5cdc0a0b40b528433fbd41a9ae88f55b3d"}, {file = "sqlalchemy-2.0.45-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:db6834900338fb13a9123307f0c2cbb1f890a8656fcd5e5448ae3ad5bbe8d312"}, {file = "sqlalchemy-2.0.45-cp38-cp38-win32.whl", hash = "sha256:1d8b4a7a8c9b537509d56d5cd10ecdcfbb95912d72480c8861524efecc6a3fff"}, {file = "sqlalchemy-2.0.45-cp38-cp38-win_amd64.whl", hash = "sha256:ebd300afd2b62679203435f596b2601adafe546cb7282d5a0cd3ed99e423720f"}, - {file = "sqlalchemy-2.0.45-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d29b2b99d527dbc66dd87c3c3248a5dd789d974a507f4653c969999fc7c1191b"}, {file = "sqlalchemy-2.0.45-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59a8b8bd9c6bedf81ad07c8bd5543eedca55fe9b8780b2b628d495ba55f8db1e"}, {file = "sqlalchemy-2.0.45-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd93c6f5d65f254ceabe97548c709e073d6da9883343adaa51bf1a913ce93f8e"}, {file = "sqlalchemy-2.0.45-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d0beadc2535157070c9c17ecf25ecec31e13c229a8f69196d7590bde8082bf1"}, @@ -4404,20 +4385,20 @@ sanic = ["sanic (>=20.12.2)"] [[package]] name = "strawberry-graphql-django" -version = "0.71.0" +version = "0.72.0" description = "Strawberry GraphQL Django extension" optional = false python-versions = "<4.0,>=3.10" groups = ["main"] files = [ - {file = "strawberry_graphql_django-0.71.0-py3-none-any.whl", hash = "sha256:ed6ae7d62c263e6bbcb631bd4e9b86429ec273ad1f20535b74be3ddbacc7f341"}, - {file = "strawberry_graphql_django-0.71.0.tar.gz", hash = "sha256:dbb23895185e5155c1a57be4668e9a8ed7166fa42d6c945f0f0b71f0d53fa566"}, + {file = "strawberry_graphql_django-0.72.0-py3-none-any.whl", hash = "sha256:b8e9e408d46142bf34635179ba7db16b396f6afb0d320feff37eb195bb592368"}, + {file = "strawberry_graphql_django-0.72.0.tar.gz", hash = "sha256:5c7c221b8e9fbb80a7f99d489407e8ad7eb872360ebf8873242be9d151c5f685"}, ] [package.dependencies] asgiref = ">=3.8" django = ">=4.2" -strawberry-graphql = ">=0.286.0" +strawberry-graphql = ">=0.288.0" [package.extras] debug-toolbar = ["django-debug-toolbar (>=6.0.0)"] @@ -5028,4 +5009,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = "^3.13" -content-hash = "7e444407fcb7c419a3482cc2ae25c8f57db183c704d8d799fddf4d26135886b3" +content-hash = "42aef0a81865318928a5b0a1eba793c1aa4d1e0fa26fbd105bd71202cd6dd02f" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 7aa355ad71..2e18087db9 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -47,7 +47,7 @@ sentry-sdk = { extras = [ "django" ], version = "^2.20.0" } slack-bolt = "^1.22.0" slack-sdk = "^3.37.0" strawberry-graphql = { extras = [ "django" ], version = "^0.288.1" } -strawberry-graphql-django = "^0.71.0" +strawberry-graphql-django = "^0.72.0" thefuzz = "^0.22.1" pyparsing = "^3.2.3" diff --git a/backend/tests/apps/common/management/commands/add_project_custom_tags_test.py b/backend/tests/apps/common/management/commands/add_project_custom_tags_test.py index 453f29f580..6efbc7995e 100644 --- a/backend/tests/apps/common/management/commands/add_project_custom_tags_test.py +++ b/backend/tests/apps/common/management/commands/add_project_custom_tags_test.py @@ -96,7 +96,7 @@ def __init__(self, key): self.key = key self.custom_tags = projects[key] - def save(self, update_fields=None): + def save(self, update_fields=None): # NOSONAR unused parameter. projects[self.key] = self.custom_tags mock_get.side_effect = lambda key: MockProject(key) diff --git a/docs/poetry.lock b/docs/poetry.lock index ebba2e8134..9c2feb9f64 100644 --- a/docs/poetry.lock +++ b/docs/poetry.lock @@ -632,14 +632,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.19.1" +version = "10.20" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pymdown_extensions-10.19.1-py3-none-any.whl", hash = "sha256:e8698a66055b1dc0dca2a7f2c9d0ea6f5faa7834a9c432e3535ab96c0c4e509b"}, - {file = "pymdown_extensions-10.19.1.tar.gz", hash = "sha256:4969c691009a389fb1f9712dd8e7bd70dcc418d15a0faf70acb5117d022f7de8"}, + {file = "pymdown_extensions-10.20-py3-none-any.whl", hash = "sha256:ea9e62add865da80a271d00bfa1c0fa085b20d133fb3fc97afdc88e682f60b2f"}, + {file = "pymdown_extensions-10.20.tar.gz", hash = "sha256:5c73566ab0cf38c6ba084cb7c5ea64a119ae0500cce754ccb682761dfea13a52"}, ] [package.dependencies] @@ -860,4 +860,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.1" python-versions = "^3.13" -content-hash = "dce53c87af4a69cea61523b945917d6b03815c403c5f0196a5a87983b321f25c" +content-hash = "f565d79d95768ab65837d4b113b14539048a2d177a2a1c90b720d8c10172ce0c" diff --git a/docs/pyproject.toml b/docs/pyproject.toml index 476ad46c93..458c7b028e 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -14,5 +14,5 @@ mkdocs = "^1.6.1" mkdocs-material = "^9.6.19" mkdocs-minify-plugin = "^0.8.0" mkdocstrings = "^1.0.0" -pymdown-extensions = "^10.14.3" +pymdown-extensions = "^10.20.0" python = "^3.13" diff --git a/frontend/__tests__/unit/components/BarChart.test.tsx b/frontend/__tests__/unit/components/BarChart.test.tsx index 31d29279cb..a97dc346bb 100644 --- a/frontend/__tests__/unit/components/BarChart.test.tsx +++ b/frontend/__tests__/unit/components/BarChart.test.tsx @@ -362,7 +362,7 @@ describe('', () => { title: 'Decimal Values', labels: ['Decimal'], days: [99.5], - requirements: [100.0], + requirements: [100], } renderWithTheme() @@ -370,7 +370,7 @@ describe('', () => { const series = JSON.parse(chartElement.dataset.series || '[]') expect(series[0].data[0].y).toBe(99.5) - expect(series[0].data[0].goals[0].value).toBe(100.0) + expect(series[0].data[0].goals[0].value).toBe(100) }) it('handles large numbers in days array', () => { diff --git a/frontend/__tests__/unit/components/CardDetailsPage.test.tsx b/frontend/__tests__/unit/components/CardDetailsPage.test.tsx index f79813061b..0537290d53 100644 --- a/frontend/__tests__/unit/components/CardDetailsPage.test.tsx +++ b/frontend/__tests__/unit/components/CardDetailsPage.test.tsx @@ -161,11 +161,16 @@ jest.mock('components/MetricsScoreCircle', () => ({ clickable?: boolean onClick?: () => void [key: string]: unknown - }) => ( -
- Score: {score} -
- ), + }) => + clickable ? ( + + ) : ( +
+ Score: {score} +
+ ), })) jest.mock('components/Milestones', () => ({ diff --git a/frontend/__tests__/unit/components/GeneralCompliantComponent.test.tsx b/frontend/__tests__/unit/components/GeneralCompliantComponent.test.tsx index 82ca64824d..03a74df274 100644 --- a/frontend/__tests__/unit/components/GeneralCompliantComponent.test.tsx +++ b/frontend/__tests__/unit/components/GeneralCompliantComponent.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import React from 'react' import type { IconType } from 'react-icons' -import { FaCertificate, FaAward } from 'react-icons/fa6' +import { FaCertificate } from 'react-icons/fa6' import '@testing-library/jest-dom' @@ -14,19 +14,6 @@ jest.mock('@heroui/tooltip', () => ({ ), })) -jest.mock('wrappers/IconWrapper', () => ({ - IconWrapper: ({ - icon: IconComponent, - className, - ...props - }: { - icon: React.ComponentType & { className?: string }> - className?: string - }) => { - return - }, -})) - import GeneralCompliantComponent from 'components/GeneralCompliantComponent' type GeneralCompliantComponentProps = { @@ -47,24 +34,30 @@ describe('GeneralCompliantComponent', () => { expect(container).toBeInTheDocument() }) - it('applies correct color for compliant=true', () => { - const { container } = render() - const svg = container.querySelector('svg') - expect(svg).toBeInTheDocument() - expect(svg).toHaveClass('text-green-400/80') + it('applies correct background color for compliant=true', () => { + render() + + const badgeContainer = screen.getByTestId('tooltip').firstElementChild + + expect(badgeContainer).toBeInTheDocument() + expect(badgeContainer).toHaveClass('bg-green-400/80') + expect(badgeContainer).toHaveClass('text-green-900/90') }) - it('applies correct color for compliant=false', () => { - const { container } = render() - const svg = container.querySelector('svg') - expect(svg).toBeInTheDocument() - expect(svg).toHaveClass('text-red-400/80') + it('applies correct background color for compliant=false', () => { + render() + + const badgeContainer = screen.getByTestId('tooltip').firstElementChild + + expect(badgeContainer).toBeInTheDocument() + expect(badgeContainer).toHaveClass('bg-red-400/80') + expect(badgeContainer).toHaveClass('text-red-900/90') }) - it('renders the correct icon structure', () => { + it('renders exactly one icon (the inner symbol)', () => { const { container } = render() const icons = container.querySelectorAll('svg') - expect(icons).toHaveLength(2) + expect(icons).toHaveLength(1) }) it('renders tooltip wrapper with title attribute', () => { @@ -78,18 +71,4 @@ describe('GeneralCompliantComponent', () => { const { container } = render() expect(container).toBeInTheDocument() }) - - it('has accessible SVG icons', () => { - const { container } = render() - const icons = container.querySelectorAll('svg') - expect(icons).toHaveLength(2) - expect(icons[0]).toBeInTheDocument() - expect(icons[1]).toBeInTheDocument() - }) - - it('renders with custom icon', () => { - const customIcon = FaAward - const { container } = render() - expect(container.querySelector('svg')).toBeInTheDocument() - }) }) diff --git a/frontend/__tests__/unit/components/Pagination.test.tsx b/frontend/__tests__/unit/components/Pagination.test.tsx index 19da1b16ce..16ee964e30 100644 --- a/frontend/__tests__/unit/components/Pagination.test.tsx +++ b/frontend/__tests__/unit/components/Pagination.test.tsx @@ -86,8 +86,10 @@ describe('', () => { expect(screen.getByRole('button', { name: `Go to page ${n}` })).toBeInTheDocument() } - // Should show exactly two "More pages" indicators - const ellipses = screen.getAllByLabelText('More pages') + const ellipsisContainers = document.querySelectorAll('div.flex.h-10.w-10') + const ellipses = Array.from(ellipsisContainers).filter((el) => + el.querySelector('svg[aria-hidden="true"]') + ) expect(ellipses).toHaveLength(2) // Should show pages around currentPage: 9, 10, 11 diff --git a/frontend/__tests__/unit/components/ProjectsDashboardDropDown.test.tsx b/frontend/__tests__/unit/components/ProjectsDashboardDropDown.test.tsx index e4fe0573d6..19a5b7cbeb 100644 --- a/frontend/__tests__/unit/components/ProjectsDashboardDropDown.test.tsx +++ b/frontend/__tests__/unit/components/ProjectsDashboardDropDown.test.tsx @@ -75,17 +75,12 @@ jest.mock('@heroui/react', () => ({ ), DropdownSection: ({ children, title }: { children: React.ReactNode; title: string }) => ( -
-
+
+ {title} -
+ {children} -
+ ), DropdownItem: (props: { children: React.ReactNode }) => { const itemText = typeof props.children === 'string' ? props.children : 'item' diff --git a/frontend/__tests__/unit/pages/About.test.tsx b/frontend/__tests__/unit/pages/About.test.tsx index ab809f5b46..9c0542ecd2 100644 --- a/frontend/__tests__/unit/pages/About.test.tsx +++ b/frontend/__tests__/unit/pages/About.test.tsx @@ -465,8 +465,10 @@ describe('About Component', () => { } ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { - if (options?.variables?.key === 'nest') { + if (query === GetProjectMetadataDocument && options?.variables?.key === 'nest') { return mockProjectData + } else if (query === GetTopContributorsDocument && options?.variables?.key === 'nest') { + return mockTopContributorsData } else if (options?.variables?.key === 'arkid15r') { return partialUserData } else if (options?.variables?.key === 'kasya' || options?.variables?.key === 'mamicidal') { diff --git a/frontend/__tests__/unit/pages/ApiKeysPage.test.tsx b/frontend/__tests__/unit/pages/ApiKeysPage.test.tsx index c214b06b46..5aed8d3781 100644 --- a/frontend/__tests__/unit/pages/ApiKeysPage.test.tsx +++ b/frontend/__tests__/unit/pages/ApiKeysPage.test.tsx @@ -22,7 +22,7 @@ jest.mock('@heroui/modal', () => { const Stub = ({ children }: { children: React.ReactNode }) => <>{children} return { Modal: ({ isOpen, children }: { isOpen: boolean; children: React.ReactNode }) => - isOpen ?
{children}
: null, + isOpen ? {children} : null, ModalContent: Stub, ModalHeader: Stub, ModalBody: Stub, diff --git a/frontend/__tests__/unit/pages/Home.test.tsx b/frontend/__tests__/unit/pages/Home.test.tsx index 3a9893245e..8300ff8a4c 100644 --- a/frontend/__tests__/unit/pages/Home.test.tsx +++ b/frontend/__tests__/unit/pages/Home.test.tsx @@ -43,7 +43,7 @@ jest.mock('components/Modal', () => { const ModalMock = jest.fn(({ isOpen, onClose, title, summary, button, description }) => { if (!isOpen) return null return ( -
+

{title}

{summary}

{description}

@@ -51,7 +51,7 @@ jest.mock('components/Modal', () => { Close {button.label} -
+ ) }) return ModalMock diff --git a/frontend/package.json b/frontend/package.json index 091f82495a..b375e02a71 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -73,7 +73,7 @@ "@graphql-codegen/typescript-operations": "^5.0.7", "@lhci/cli": "^0.15.1", "@playwright/test": "^1.57.0", - "@swc/core": "^1.15.7", + "@swc/core": "^1.15.8", "@swc/jest": "^0.2.39", "@tailwindcss/postcss": "^4.1.18", "@testing-library/jest-dom": "^6.9.1", @@ -86,13 +86,13 @@ "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", "@types/react-gtm-module": "^2.0.4", - "@typescript-eslint/eslint-plugin": "^8.50.1", - "@typescript-eslint/parser": "^8.50.1", + "@typescript-eslint/eslint-plugin": "^8.51.0", + "@typescript-eslint/parser": "^8.51.0", "eslint": "^9.39.2", "eslint-config-next": "^16.1.1", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-alias": "^1.1.2", - "eslint-plugin-jest": "^29.11.1", + "eslint-plugin-jest": "^29.12.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-react": "^7.37.5", @@ -111,7 +111,7 @@ "ts-jest": "^29.4.6", "ts-node": "^10.9.2", "typescript": "~5.9.3", - "typescript-eslint": "^8.50.1", + "typescript-eslint": "^8.51.0", "util": "^0.12.5" }, "engines": { diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 61ba896c3c..2168179980 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: version: 16.1.1(next@16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) '@sentry/nextjs': specifier: ^10.32.1 - version: 10.32.1(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18))) + version: 10.32.1(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18))) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) @@ -79,7 +79,7 @@ importers: version: 3.3.1 eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) framer-motion: specifier: ^12.23.26 version: 12.23.26(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -172,11 +172,11 @@ importers: specifier: ^1.57.0 version: 1.57.0 '@swc/core': - specifier: ^1.15.7 - version: 1.15.7(@swc/helpers@0.5.18) + specifier: ^1.15.8 + version: 1.15.8(@swc/helpers@0.5.18) '@swc/jest': specifier: ^0.2.39 - version: 0.2.39(@swc/core@1.15.7(@swc/helpers@0.5.18)) + version: 0.2.39(@swc/core@1.15.8(@swc/helpers@0.5.18)) '@tailwindcss/postcss': specifier: ^4.1.18 version: 4.1.18 @@ -211,17 +211,17 @@ importers: specifier: ^2.0.4 version: 2.0.4 '@typescript-eslint/eslint-plugin': - specifier: ^8.50.1 - version: 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.51.0 + version: 8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: ^8.50.1 - version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.51.0 + version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.39.2 version: 9.39.2(jiti@2.6.1) eslint-config-next: specifier: ^16.1.1 - version: 16.1.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 16.1.1(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-config-prettier: specifier: ^10.1.8 version: 10.1.8(eslint@9.39.2(jiti@2.6.1)) @@ -229,8 +229,8 @@ importers: specifier: ^1.1.2 version: 1.1.2(eslint-plugin-import@2.32.0) eslint-plugin-jest: - specifier: ^29.11.1 - version: 29.11.1(@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3) + specifier: ^29.12.0 + version: 29.12.0(@typescript-eslint/eslint-plugin@8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3) eslint-plugin-jsx-a11y: specifier: ^6.10.2 version: 6.10.2(eslint@9.39.2(jiti@2.6.1)) @@ -254,7 +254,7 @@ importers: version: 2.0.1 jest: specifier: ^30.2.0 - version: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + version: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) jest-axe: specifier: ^10.0.0 version: 10.0.0 @@ -278,16 +278,16 @@ importers: version: 4.1.18 ts-jest: specifier: ^29.4.6 - version: 29.4.6(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3) + version: 10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3) typescript: specifier: ~5.9.3 version: 5.9.3 typescript-eslint: - specifier: ^8.50.1 - version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.51.0 + version: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) util: specifier: ^0.12.5 version: 0.12.5 @@ -566,8 +566,8 @@ packages: resolution: {integrity: sha512-CsFmA3u3c2QoLDTfEpGr4t25fjMU31nyvse7IzWTvb0ZycuPjMjb0fjlheh+PbhBYb9YLugnT2uY6Mwcg1o+Zg==} engines: {node: '>=18.0.0'} - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -2971,68 +2971,68 @@ packages: peerDependencies: '@svgdotjs/svg.js': ^3.2.4 - '@swc/core-darwin-arm64@1.15.7': - resolution: {integrity: sha512-+hNVUfezUid7LeSHqnhoC6Gh3BROABxjlDNInuZ/fie1RUxaEX4qzDwdTgozJELgHhvYxyPIg1ro8ibnKtgO4g==} + '@swc/core-darwin-arm64@1.15.8': + resolution: {integrity: sha512-M9cK5GwyWWRkRGwwCbREuj6r8jKdES/haCZ3Xckgkl8MUQJZA3XB7IXXK1IXRNeLjg6m7cnoMICpXv1v1hlJOg==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.15.7': - resolution: {integrity: sha512-ZAFuvtSYZTuXPcrhanaD5eyp27H8LlDzx2NAeVyH0FchYcuXf0h5/k3GL9ZU6Jw9eQ63R1E8KBgpXEJlgRwZUQ==} + '@swc/core-darwin-x64@1.15.8': + resolution: {integrity: sha512-j47DasuOvXl80sKJHSi2X25l44CMc3VDhlJwA7oewC1nV1VsSzwX+KOwE5tLnfORvVJJyeiXgJORNYg4jeIjYQ==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.15.7': - resolution: {integrity: sha512-K3HTYocpqnOw8KcD8SBFxiDHjIma7G/X+bLdfWqf+qzETNBrzOub/IEkq9UaeupaJiZJkPptr/2EhEXXWryS/A==} + '@swc/core-linux-arm-gnueabihf@1.15.8': + resolution: {integrity: sha512-siAzDENu2rUbwr9+fayWa26r5A9fol1iORG53HWxQL1J8ym4k7xt9eME0dMPXlYZDytK5r9sW8zEA10F2U3Xwg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.15.7': - resolution: {integrity: sha512-HCnVIlsLnCtQ3uXcXgWrvQ6SAraskLA9QJo9ykTnqTH6TvUYqEta+TdTdGjzngD6TOE7XjlAiUs/RBtU8Z0t+Q==} + '@swc/core-linux-arm64-gnu@1.15.8': + resolution: {integrity: sha512-o+1y5u6k2FfPYbTRUPvurwzNt5qd0NTumCTFscCNuBksycloXY16J8L+SMW5QRX59n4Hp9EmFa3vpvNHRVv1+Q==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.15.7': - resolution: {integrity: sha512-/OOp9UZBg4v2q9+x/U21Jtld0Wb8ghzBScwhscI7YvoSh4E8RALaJ1msV8V8AKkBkZH7FUAFB7Vbv0oVzZsezA==} + '@swc/core-linux-arm64-musl@1.15.8': + resolution: {integrity: sha512-koiCqL09EwOP1S2RShCI7NbsQuG6r2brTqUYE7pV7kZm9O17wZ0LSz22m6gVibpwEnw8jI3IE1yYsQTVpluALw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.15.7': - resolution: {integrity: sha512-VBbs4gtD4XQxrHuQ2/2+TDZpPQQgrOHYRnS6SyJW+dw0Nj/OomRqH+n5Z4e/TgKRRbieufipeIGvADYC/90PYQ==} + '@swc/core-linux-x64-gnu@1.15.8': + resolution: {integrity: sha512-4p6lOMU3bC+Vd5ARtKJ/FxpIC5G8v3XLoPEZ5s7mLR8h7411HWC/LmTXDHcrSXRC55zvAVia1eldy6zDLz8iFQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.15.7': - resolution: {integrity: sha512-kVuy2unodso6p0rMauS2zby8/bhzoGRYxBDyD6i2tls/fEYAE74oP0VPFzxIyHaIjK1SN6u5TgvV9MpyJ5xVug==} + '@swc/core-linux-x64-musl@1.15.8': + resolution: {integrity: sha512-z3XBnbrZAL+6xDGAhJoN4lOueIxC/8rGrJ9tg+fEaeqLEuAtHSW2QHDHxDwkxZMjuF/pZ6MUTjHjbp8wLbuRLA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.15.7': - resolution: {integrity: sha512-uddYoo5Xmo1XKLhAnh4NBIyy5d0xk33x1sX3nIJboFySLNz878ksCFCZ3IBqrt1Za0gaoIWoOSSSk0eNhAc/sw==} + '@swc/core-win32-arm64-msvc@1.15.8': + resolution: {integrity: sha512-djQPJ9Rh9vP8GTS/Df3hcc6XP6xnG5c8qsngWId/BLA9oX6C7UzCPAn74BG/wGb9a6j4w3RINuoaieJB3t+7iQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.15.7': - resolution: {integrity: sha512-rqq8JjNMLx3QNlh0aPTtN/4+BGLEHC94rj9mkH1stoNRf3ra6IksNHMHy+V1HUqElEgcZyx+0yeXx3eLOTcoFw==} + '@swc/core-win32-ia32-msvc@1.15.8': + resolution: {integrity: sha512-/wfAgxORg2VBaUoFdytcVBVCgf1isWZIEXB9MZEUty4wwK93M/PxAkjifOho9RN3WrM3inPLabICRCEgdHpKKQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.15.7': - resolution: {integrity: sha512-4BK06EGdPnuplgcNhmSbOIiLdRgHYX3v1nl4HXo5uo4GZMfllXaCyBUes+0ePRfwbn9OFgVhCWPcYYjMT6hycQ==} + '@swc/core-win32-x64-msvc@1.15.8': + resolution: {integrity: sha512-GpMePrh9Sl4d61o4KAHOOv5is5+zt6BEXCOCgs/H0FLGeii7j9bWDE8ExvKFy2GRRZVNR1ugsnzaGWHKM6kuzA==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.15.7': - resolution: {integrity: sha512-kTGB8XI7P+pTKW83tnUEDVP4zduF951u3UAOn5eTi0vyW6MvL56A3+ggMdfuVFtDI0/DsbSzf5z34HVBbuScWw==} + '@swc/core@1.15.8': + resolution: {integrity: sha512-T8keoJjXaSUoVBCIjgL6wAnhADIb09GOELzKg10CjNg+vLX48P93SME6jTfte9MZIm5m+Il57H3rTSk/0kzDUw==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -3324,63 +3324,63 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.50.1': - resolution: {integrity: sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==} + '@typescript-eslint/eslint-plugin@8.51.0': + resolution: {integrity: sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.50.1 + '@typescript-eslint/parser': ^8.51.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.50.1': - resolution: {integrity: sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==} + '@typescript-eslint/parser@8.51.0': + resolution: {integrity: sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.50.1': - resolution: {integrity: sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==} + '@typescript-eslint/project-service@8.51.0': + resolution: {integrity: sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.50.1': - resolution: {integrity: sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==} + '@typescript-eslint/scope-manager@8.51.0': + resolution: {integrity: sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.50.1': - resolution: {integrity: sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==} + '@typescript-eslint/tsconfig-utils@8.51.0': + resolution: {integrity: sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.50.1': - resolution: {integrity: sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==} + '@typescript-eslint/type-utils@8.51.0': + resolution: {integrity: sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.50.1': - resolution: {integrity: sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==} + '@typescript-eslint/types@8.51.0': + resolution: {integrity: sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.50.1': - resolution: {integrity: sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==} + '@typescript-eslint/typescript-estree@8.51.0': + resolution: {integrity: sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.50.1': - resolution: {integrity: sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==} + '@typescript-eslint/utils@8.51.0': + resolution: {integrity: sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.50.1': - resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==} + '@typescript-eslint/visitor-keys@8.51.0': + resolution: {integrity: sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3916,8 +3916,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001761: - resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} + caniuse-lite@1.0.30001762: + resolution: {integrity: sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==} capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -4515,8 +4515,8 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-jest@29.11.1: - resolution: {integrity: sha512-EP2+xBHm7yMRSprEAui15zTnXAobGVc/Ub50OW0o1oQum2iyidfsCmpzaxEZg8f1XPMcIZEVvomla31VUG6YeQ==} + eslint-plugin-jest@29.12.0: + resolution: {integrity: sha512-dOMLGkl5vCDZo/KcsmzJkkYJUH+SDLls4PLBj8Aw86x5BHdXkygMGdfnqikJ8RUgEx3MHni09B5cebZF5+4rrQ==} engines: {node: ^20.12.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@typescript-eslint/eslint-plugin': ^8.0.0 @@ -4595,8 +4595,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -6435,8 +6435,8 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -7203,8 +7203,8 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript-eslint@8.50.1: - resolution: {integrity: sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==} + typescript-eslint@8.51.0: + resolution: {integrity: sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -7553,8 +7553,8 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.2.1: - resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==} + zod@4.3.4: + resolution: {integrity: sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==} snapshots: @@ -7870,7 +7870,7 @@ snapshots: '@whatwg-node/promise-helpers': 1.3.2 tslib: 2.8.1 - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 @@ -9764,7 +9764,7 @@ snapshots: jest-util: 30.2.0 slash: 3.0.0 - '@jest/core@30.2.0(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3))': + '@jest/core@30.2.0(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3))': dependencies: '@jest/console': 30.2.0 '@jest/pattern': 30.0.1 @@ -9779,7 +9779,7 @@ snapshots: exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.2.0 - jest-config: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + jest-config: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) jest-haste-map: 30.2.0 jest-message-util: 30.2.0 jest-regex-util: 30.0.1 @@ -11317,7 +11317,7 @@ snapshots: '@sentry/utils': 7.120.4 localforage: 1.10.0 - '@sentry/nextjs@10.32.1(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18)))': + '@sentry/nextjs@10.32.1(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(next@16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18)))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.38.0 @@ -11329,7 +11329,7 @@ snapshots: '@sentry/opentelemetry': 10.32.1(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) '@sentry/react': 10.32.1(react@19.2.3) '@sentry/vercel-edge': 10.32.1 - '@sentry/webpack-plugin': 4.6.1(webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18))) + '@sentry/webpack-plugin': 4.6.1(webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18))) next: 16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) resolve: 1.22.8 rollup: 4.54.0 @@ -11435,12 +11435,12 @@ snapshots: '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) '@sentry/core': 10.32.1 - '@sentry/webpack-plugin@4.6.1(webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18)))': + '@sentry/webpack-plugin@4.6.1(webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18)))': dependencies: '@sentry/bundler-plugin-core': 4.6.1 unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18)) + webpack: 5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18)) transitivePeerDependencies: - encoding - supports-color @@ -11476,51 +11476,51 @@ snapshots: dependencies: '@svgdotjs/svg.js': 3.2.5 - '@swc/core-darwin-arm64@1.15.7': + '@swc/core-darwin-arm64@1.15.8': optional: true - '@swc/core-darwin-x64@1.15.7': + '@swc/core-darwin-x64@1.15.8': optional: true - '@swc/core-linux-arm-gnueabihf@1.15.7': + '@swc/core-linux-arm-gnueabihf@1.15.8': optional: true - '@swc/core-linux-arm64-gnu@1.15.7': + '@swc/core-linux-arm64-gnu@1.15.8': optional: true - '@swc/core-linux-arm64-musl@1.15.7': + '@swc/core-linux-arm64-musl@1.15.8': optional: true - '@swc/core-linux-x64-gnu@1.15.7': + '@swc/core-linux-x64-gnu@1.15.8': optional: true - '@swc/core-linux-x64-musl@1.15.7': + '@swc/core-linux-x64-musl@1.15.8': optional: true - '@swc/core-win32-arm64-msvc@1.15.7': + '@swc/core-win32-arm64-msvc@1.15.8': optional: true - '@swc/core-win32-ia32-msvc@1.15.7': + '@swc/core-win32-ia32-msvc@1.15.8': optional: true - '@swc/core-win32-x64-msvc@1.15.7': + '@swc/core-win32-x64-msvc@1.15.8': optional: true - '@swc/core@1.15.7(@swc/helpers@0.5.18)': + '@swc/core@1.15.8(@swc/helpers@0.5.18)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.25 optionalDependencies: - '@swc/core-darwin-arm64': 1.15.7 - '@swc/core-darwin-x64': 1.15.7 - '@swc/core-linux-arm-gnueabihf': 1.15.7 - '@swc/core-linux-arm64-gnu': 1.15.7 - '@swc/core-linux-arm64-musl': 1.15.7 - '@swc/core-linux-x64-gnu': 1.15.7 - '@swc/core-linux-x64-musl': 1.15.7 - '@swc/core-win32-arm64-msvc': 1.15.7 - '@swc/core-win32-ia32-msvc': 1.15.7 - '@swc/core-win32-x64-msvc': 1.15.7 + '@swc/core-darwin-arm64': 1.15.8 + '@swc/core-darwin-x64': 1.15.8 + '@swc/core-linux-arm-gnueabihf': 1.15.8 + '@swc/core-linux-arm64-gnu': 1.15.8 + '@swc/core-linux-arm64-musl': 1.15.8 + '@swc/core-linux-x64-gnu': 1.15.8 + '@swc/core-linux-x64-musl': 1.15.8 + '@swc/core-win32-arm64-msvc': 1.15.8 + '@swc/core-win32-ia32-msvc': 1.15.8 + '@swc/core-win32-x64-msvc': 1.15.8 '@swc/helpers': 0.5.18 '@swc/counter@0.1.3': {} @@ -11533,10 +11533,10 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/jest@0.2.39(@swc/core@1.15.7(@swc/helpers@0.5.18))': + '@swc/jest@0.2.39(@swc/core@1.15.8(@swc/helpers@0.5.18))': dependencies: '@jest/create-cache-key-function': 30.2.0 - '@swc/core': 1.15.7(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.18) '@swc/counter': 0.1.3 jsonc-parser: 3.3.1 @@ -11819,14 +11819,14 @@ snapshots: '@types/node': 25.0.3 optional: true - '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.50.1 - '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.50.1 + '@typescript-eslint/parser': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.51.0 + '@typescript-eslint/type-utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.51.0 eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 @@ -11835,41 +11835,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.50.1 - '@typescript-eslint/types': 8.50.1 - '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.50.1 + '@typescript-eslint/scope-manager': 8.51.0 + '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.51.0 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.50.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.51.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) - '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/tsconfig-utils': 8.51.0(typescript@5.9.3) + '@typescript-eslint/types': 8.51.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.50.1': + '@typescript-eslint/scope-manager@8.51.0': dependencies: - '@typescript-eslint/types': 8.50.1 - '@typescript-eslint/visitor-keys': 8.50.1 + '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/visitor-keys': 8.51.0 - '@typescript-eslint/tsconfig-utils@8.50.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.51.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.50.1 - '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.3.0(typescript@5.9.3) @@ -11877,14 +11877,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.50.1': {} + '@typescript-eslint/types@8.51.0': {} - '@typescript-eslint/typescript-estree@8.50.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.51.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.50.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) - '@typescript-eslint/types': 8.50.1 - '@typescript-eslint/visitor-keys': 8.50.1 + '@typescript-eslint/project-service': 8.51.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.51.0(typescript@5.9.3) + '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/visitor-keys': 8.51.0 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 @@ -11894,20 +11894,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.50.1 - '@typescript-eslint/types': 8.50.1 - '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.51.0 + '@typescript-eslint/types': 8.51.0 + '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.50.1': + '@typescript-eslint/visitor-keys@8.51.0': dependencies: - '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/types': 8.51.0 eslint-visitor-keys: 4.2.1 '@ungap/structured-clone@1.3.0': {} @@ -12406,7 +12406,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.14.0 + qs: 6.14.1 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 @@ -12429,7 +12429,7 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.11 - caniuse-lite: 1.0.30001761 + caniuse-lite: 1.0.30001762 electron-to-chromium: 1.5.267 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -12476,7 +12476,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001761: {} + caniuse-lite@1.0.30001762: {} capital-case@1.0.4: dependencies: @@ -13047,18 +13047,18 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-next@16.1.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@16.1.1(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.1.1 eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1)) globals: 16.4.0 - typescript-eslint: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -13073,7 +13073,7 @@ snapshots: eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0): dependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) eslint-import-resolver-node@0.3.9: dependencies: @@ -13094,22 +13094,22 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -13120,7 +13120,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -13132,19 +13132,19 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@29.11.1(@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3): + eslint-plugin-jest@29.12.0(@typescript-eslint/eslint-plugin@8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - jest: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + '@typescript-eslint/eslint-plugin': 8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + jest: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) transitivePeerDependencies: - supports-color - typescript @@ -13184,8 +13184,8 @@ snapshots: '@babel/parser': 7.28.5 eslint: 9.39.2(jiti@2.6.1) hermes-parser: 0.25.1 - zod: 4.2.1 - zod-validation-error: 4.0.2(zod@4.2.1) + zod: 4.3.4 + zod-validation-error: 4.0.2(zod@4.3.4) transitivePeerDependencies: - supports-color @@ -13227,7 +13227,7 @@ snapshots: eslint@9.39.2(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -13247,7 +13247,7 @@ snapshots: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -13274,7 +13274,7 @@ snapshots: esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -13348,7 +13348,7 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.14.0 + qs: 6.14.1 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2 @@ -14148,15 +14148,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): + jest-cli@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): dependencies: - '@jest/core': 30.2.0(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + '@jest/core': 30.2.0(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) '@jest/test-result': 30.2.0 '@jest/types': 30.2.0 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + jest-config: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) jest-util: 30.2.0 jest-validate: 30.2.0 yargs: 17.7.2 @@ -14167,7 +14167,7 @@ snapshots: - supports-color - ts-node - jest-config@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): + jest-config@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): dependencies: '@babel/core': 7.28.5 '@jest/get-type': 30.1.0 @@ -14195,7 +14195,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 25.0.3 - ts-node: 10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3) + ts-node: 10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -14449,12 +14449,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): + jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)): dependencies: - '@jest/core': 30.2.0(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + '@jest/core': 30.2.0(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) '@jest/types': 30.2.0 import-local: 3.2.0 - jest-cli: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + jest-cli: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -14909,7 +14909,7 @@ snapshots: '@next/env': 16.1.1 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.9.11 - caniuse-lite: 1.0.30001761 + caniuse-lite: 1.0.30001762 postcss: 8.4.31 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -15337,7 +15337,7 @@ snapshots: pure-rand@7.0.1: {} - qs@6.14.0: + qs@6.14.1: dependencies: side-channel: 1.1.0 @@ -16015,16 +16015,16 @@ snapshots: - bare-abort-controller - react-native-b4a - terser-webpack-plugin@5.3.16(@swc/core@1.15.7(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18))): + terser-webpack-plugin@5.3.16(@swc/core@1.15.8(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18))): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.1 - webpack: 5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18)) + webpack: 5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18)) optionalDependencies: - '@swc/core': 1.15.7(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.18) terser@5.44.1: dependencies: @@ -16110,12 +16110,12 @@ snapshots: dependencies: typescript: 5.9.3 - ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) + jest: 30.2.0(@types/node@25.0.3)(ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -16132,7 +16132,7 @@ snapshots: ts-log@2.2.7: {} - ts-node@10.9.2(@swc/core@1.15.7(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.8(@swc/helpers@0.5.18))(@types/node@25.0.3)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 @@ -16150,7 +16150,7 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.15.7(@swc/helpers@0.5.18) + '@swc/core': 1.15.8(@swc/helpers@0.5.18) tsconfig-paths@3.15.0: dependencies: @@ -16223,12 +16223,12 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript-eslint@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -16387,7 +16387,7 @@ snapshots: webpack-virtual-modules@0.5.0: {} - webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18)): + webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -16411,7 +16411,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(@swc/core@1.15.7(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.7(@swc/helpers@0.5.18))) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.8(@swc/helpers@0.5.18))(webpack@5.103.0(@swc/core@1.15.8(@swc/helpers@0.5.18))) watchpack: 2.5.0 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -16602,10 +16602,10 @@ snapshots: toposort: 2.0.2 type-fest: 2.19.0 - zod-validation-error@4.0.2(zod@4.2.1): + zod-validation-error@4.0.2(zod@4.3.4): dependencies: - zod: 4.2.1 + zod: 4.3.4 zod@3.25.76: {} - zod@4.2.1: {} + zod@4.3.4: {} diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index 3310ee9dfa..aafe8282db 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -5,7 +5,7 @@ import upperFirst from 'lodash/upperFirst' import millify from 'millify' import Image from 'next/image' import Link from 'next/link' -import { useEffect, useState } from 'react' +import { useEffect } from 'react' import { FaMapSigns, FaTools } from 'react-icons/fa' import { FaCircleCheck, FaClock, FaScroll, FaBullseye, FaUser, FaUsersGear } from 'react-icons/fa6' import { HiUserGroup } from 'react-icons/hi' @@ -16,8 +16,6 @@ import { GetTopContributorsDocument, } from 'types/__generated__/projectQueries.generated' import { GetLeaderDataDocument } from 'types/__generated__/userQueries.generated' -import type { Contributor } from 'types/contributor' -import type { Project } from 'types/project' import { technologies, missionContent, @@ -62,56 +60,46 @@ const getMilestoneIcon = (progress: number) => { } const About = () => { - const { data: projectMetadataResponse, error: projectMetadataRequestError } = useQuery( - GetProjectMetadataDocument, - { - variables: { key: projectKey }, - } - ) + const { + data: projectMetadataResponse, + loading: projectMetadataLoading, + error: projectMetadataRequestError, + } = useQuery(GetProjectMetadataDocument, { + variables: { key: projectKey }, + }) - const { data: topContributorsResponse, error: topContributorsRequestError } = useQuery( - GetTopContributorsDocument, - { - variables: { - excludedUsernames: Object.keys(leaders), - hasFullName: true, - key: projectKey, - limit: 24, - }, - } - ) + const { + data: topContributorsResponse, + loading: topContributorsLoading, + error: topContributorsRequestError, + } = useQuery(GetTopContributorsDocument, { + variables: { + excludedUsernames: Object.keys(leaders), + hasFullName: true, + key: projectKey, + limit: 24, + }, + }) const { leadersData, isLoading: leadersLoading } = useLeadersData() - const [projectMetadata, setProjectMetadata] = useState(null) - const [topContributors, setTopContributors] = useState([]) + // Derive data directly from response to prevent race conditions. + const projectMetadata = projectMetadataResponse?.project + const topContributors = topContributorsResponse?.topContributors useEffect(() => { - if (projectMetadataResponse?.project) { - setProjectMetadata(projectMetadataResponse.project) - } - if (projectMetadataRequestError) { handleAppError(projectMetadataRequestError) } - }, [projectMetadataResponse, projectMetadataRequestError]) + }, [projectMetadataRequestError]) useEffect(() => { - if (topContributorsResponse?.topContributors) { - setTopContributors(topContributorsResponse.topContributors) - } - if (topContributorsRequestError) { handleAppError(topContributorsRequestError) } - }, [topContributorsResponse, topContributorsRequestError]) + }, [topContributorsRequestError]) - const isLoading = - !projectMetadataResponse || - !topContributorsResponse || - (projectMetadataRequestError && !projectMetadata) || - (topContributorsRequestError && !topContributors) || - leadersLoading + const isLoading = leadersLoading || projectMetadataLoading || topContributorsLoading if (isLoading) { return diff --git a/frontend/src/app/api/auth/[...nextauth]/route.ts b/frontend/src/app/api/auth/[...nextauth]/route.ts index b527298819..990b0e2617 100644 --- a/frontend/src/app/api/auth/[...nextauth]/route.ts +++ b/frontend/src/app/api/auth/[...nextauth]/route.ts @@ -18,7 +18,10 @@ async function checkIfProjectLeader(login: string): Promise { }) return data?.isProjectLeader ?? false } catch (err) { - throw new Error('Failed to fetch project leader status Error', err) + throw new Error( + `Failed to fetch project leader status: ${err instanceof Error ? err.message : String(err)}`, + { cause: err } + ) } } @@ -32,7 +35,10 @@ async function checkIfMentor(login: string): Promise { }) return data?.isMentor ?? false } catch (err) { - throw new Error('Failed to fetch mentor status Error', err) + throw new Error( + `Failed to fetch mentor status: ${err instanceof Error ? err.message : String(err)}`, + { cause: err } + ) } } diff --git a/frontend/src/app/board/[year]/candidates/page.tsx b/frontend/src/app/board/[year]/candidates/page.tsx index 2f0c03b061..081e6840bc 100644 --- a/frontend/src/app/board/[year]/candidates/page.tsx +++ b/frontend/src/app/board/[year]/candidates/page.tsx @@ -87,20 +87,21 @@ type CandidateWithSnapshot = Candidate & { const BoardCandidatesPage = () => { const { year } = useParams<{ year: string }>() const [candidates, setCandidates] = useState([]) - const [isLoading, setIsLoading] = useState(true) - const { data: graphQLData, error: graphQLRequestError } = useQuery(GetBoardCandidatesDocument, { + const { + data: graphQLData, + error: graphQLRequestError, + loading, + } = useQuery(GetBoardCandidatesDocument, { variables: { year: Number.parseInt(year) }, }) useEffect(() => { if (graphQLData?.boardOfDirectors) { setCandidates(graphQLData.boardOfDirectors.candidates || []) - setIsLoading(false) } if (graphQLRequestError) { handleAppError(graphQLRequestError) - setIsLoading(false) } }, [graphQLData, graphQLRequestError]) @@ -676,7 +677,7 @@ const BoardCandidatesPage = () => { ) } - if (isLoading) { + if (loading) { return } diff --git a/frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx b/frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx index c8bcf54c50..666cd9a937 100644 --- a/frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx +++ b/frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx @@ -36,21 +36,29 @@ const ModuleIssueDetailsPage = () => { const isOverdue = deadlineUTC < todayUTC const daysLeft = Math.ceil((deadlineUTC.getTime() - todayUTC.getTime()) / (1000 * 60 * 60 * 24)) - const statusText = isOverdue - ? '(overdue)' - : daysLeft === 0 - ? '(today)' - : `(${daysLeft} days left)` + let statusText: string + if (isOverdue) { + statusText = '(overdue)' + } else if (daysLeft === 0) { + statusText = '(today)' + } else { + statusText = `(${daysLeft} days left)` + } const displayDate = deadlineDate.toLocaleDateString() + let color: string + if (isOverdue) { + color = 'text-[#DA3633]' + } else if (daysLeft <= 3) { + color = 'text-[#F59E0B]' + } else { + color = 'text-gray-600 dark:text-gray-300' + } + return { text: `${displayDate} ${statusText}`, - color: isOverdue - ? 'text-[#DA3633]' - : daysLeft <= 3 - ? 'text-[#F59E0B]' - : 'text-gray-600 dark:text-gray-300', + color, } } const { data, loading, error } = useQuery(GetModuleIssueViewDocument, { @@ -101,6 +109,47 @@ const ModuleIssueDetailsPage = () => { const remainingLabels = labels.length - visibleLabels.length const canEditDeadline = assignees.length > 0 + let issueStatusClass: string + let issueStatusLabel: string + if (issue.state === 'open') { + issueStatusClass = 'bg-[#238636] text-white' + issueStatusLabel = 'Open' + } else if (issue.isMerged) { + issueStatusClass = 'bg-[#8657E5] text-white' + issueStatusLabel = 'Merged' + } else { + issueStatusClass = 'bg-[#DA3633] text-white' + issueStatusLabel = 'Closed' + } + + const getPRStatus = (pr: Exclude[0]) => { + let backgroundColor: string + let label: string + if (pr.state === 'closed' && pr.mergedAt) { + backgroundColor = '#8657E5' + label = 'Merged' + } else if (pr.state === 'closed') { + backgroundColor = '#DA3633' + label = 'Closed' + } else { + backgroundColor = '#238636' + label = 'Open' + } + return { backgroundColor, label } + } + + const getAssignButtonTitle = (assigning: boolean) => { + let title: string + if (!issueId) { + title = 'Loading issue…' + } else if (assigning) { + title = 'Assigning…' + } else { + title = 'Assign to this user' + } + return title + } + return (
@@ -114,15 +163,9 @@ const ModuleIssueDetailsPage = () => { {issue.organizationName}/{issue.repositoryName} • #{issue.number} - {issue.state === 'open' ? 'Open' : issue.isMerged ? 'Merged' : 'Closed'} + {issueStatusLabel}
@@ -340,28 +383,17 @@ const ModuleIssueDetailsPage = () => {
- {pr.state === 'closed' && pr.mergedAt ? ( - - Merged - - ) : pr.state === 'closed' ? ( - - Closed - - ) : ( - - Open - - )} + {(() => { + const { backgroundColor, label } = getPRStatus(pr) + return ( + + {label} + + ) + })()}
)) @@ -415,9 +447,7 @@ const ModuleIssueDetailsPage = () => { }) }} className={`${getButtonClassName(!issueId || assigning)} px-3 py-1`} - title={ - !issueId ? 'Loading issue…' : assigning ? 'Assigning…' : 'Assign to this user' - } + title={getAssignButtonTitle(assigning)} > Assign diff --git a/frontend/src/app/settings/api-keys/page.tsx b/frontend/src/app/settings/api-keys/page.tsx index b042c21955..d65febe491 100644 --- a/frontend/src/app/settings/api-keys/page.tsx +++ b/frontend/src/app/settings/api-keys/page.tsx @@ -5,7 +5,7 @@ import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@herou import { Input } from '@heroui/react' import { addToast } from '@heroui/toast' import { format, addDays } from 'date-fns' -import { useState } from 'react' +import React, { useState } from 'react' import { FaInfoCircle } from 'react-icons/fa' import { FaSpinner, FaKey, FaPlus, FaCopy, FaEye, FaEyeSlash, FaTrash } from 'react-icons/fa6' import { @@ -14,11 +14,80 @@ import { RevokeApiKeyDocument, } from 'types/__generated__/apiKeyQueries.generated' import type { ApiKey } from 'types/apiKey' +import LoadingSpinner from 'components/LoadingSpinner' import SecondaryCard from 'components/SecondaryCard' import { ApiKeysSkeleton } from 'components/skeletons/ApiKeySkelton' const MAX_ACTIVE_KEYS = 3 +// Content state components +const ErrorState = () => ( +
+ Error loading API keys +
+) + +const EmptyState = () => ( +
+ You don't have any API keys yet. +
+) + +interface ApiKeysTableProps { + data: { apiKeys?: ApiKey[] } | undefined + onRevoke: (key: ApiKey) => void +} + +const ApiKeysTable = ({ data, onRevoke }: ApiKeysTableProps) => ( +
+ + + + + + + + + + + + {(data?.apiKeys ?? []).map((key: ApiKey) => ( + + + + + + + + ))} + +
NameIDCreatedExpiresActions
{key.name}{key.uuid}{format(new Date(key.createdAt), 'PP')} + {key.expiresAt ? format(new Date(key.expiresAt), 'PP') : 'Never'} + + +
+
+) + +type ContentType = 'error' | 'loading' | 'empty' | 'table' + +const getContentComponents = ( + data: { apiKeys?: ApiKey[] } | undefined, + onRevoke: (key: ApiKey) => void +): Record React.ReactNode> => ({ + error: () => , + loading: () => , + empty: () => , + table: () => , +}) + export default function Page() { const [isCreateModalOpen, setIsCreateModalOpen] = useState(false) const [newKeyName, setNewKeyName] = useState('') @@ -70,6 +139,21 @@ export default function Page() { const canCreateNewKey = activeKeyCount < MAX_ACTIVE_KEYS const defaultExpiryDate = format(addDays(new Date(), 30), 'yyyy-MM-dd') + const getContentType = (): ContentType => { + if (error) { + return 'error' + } else if (loading) { + return 'loading' + } else if (data?.apiKeys?.length === 0) { + return 'empty' + } else { + return 'table' + } + } + + const contentType = getContentType() + const contentComponents = getContentComponents(data, setKeyToRevoke) + const handleCreateKey = () => { if (!newKeyName.trim()) { addToast({ title: 'Error', description: 'Please provide a name', color: 'danger' }) @@ -202,58 +286,7 @@ export default function Page() { - {error ? ( -
- Error loading API keys -
- ) : loading ? ( -
- -
- ) : !data?.apiKeys?.length ? ( -
- You don't have any API keys yet. -
- ) : ( -
- - - - - - - - - - - - {data.apiKeys.map((key: ApiKey) => ( - - - - - - - - ))} - -
NameIDCreatedExpiresActions
{key.name}{key.uuid}{format(new Date(key.createdAt), 'PP')} - {key.expiresAt ? format(new Date(key.expiresAt), 'PP') : 'Never'} - - -
-
- )} + {contentComponents[contentType]()} diff --git a/frontend/src/components/ActionButton.tsx b/frontend/src/components/ActionButton.tsx index c31d74d1c1..0d8bcee1e8 100644 --- a/frontend/src/components/ActionButton.tsx +++ b/frontend/src/components/ActionButton.tsx @@ -6,11 +6,18 @@ import React, { ReactNode } from 'react' interface ActionButtonProps { url?: string onClick?: () => void + onKeyDown?: (e: React.KeyboardEvent) => void tooltipLabel?: string children: ReactNode } -const ActionButton: React.FC = ({ url, onClick, tooltipLabel, children }) => { +const ActionButton: React.FC = ({ + url, + onClick, + onKeyDown, + tooltipLabel, + children, +}) => { const baseStyles = 'flex items-center gap-2 px-2 py-2 rounded-md border border-[#1D7BD7] transition-all whitespace-nowrap justify-center bg-transparent text-[#1D7BD7] hover:bg-[#1D7BD7] hover:text-white dark:hover:text-white' @@ -24,6 +31,7 @@ const ActionButton: React.FC = ({ url, onClick, tooltipLabel, data-tooltip-id="button-tooltip" data-tooltip-content={tooltipLabel} onClick={onClick} + onKeyDown={onKeyDown} aria-label={tooltipLabel} > {children} @@ -31,7 +39,12 @@ const ActionButton: React.FC = ({ url, onClick, tooltipLabel, ) : ( - diff --git a/frontend/src/components/Card.tsx b/frontend/src/components/Card.tsx index 35594cc56e..1a99fce4f0 100644 --- a/frontend/src/components/Card.tsx +++ b/frontend/src/components/Card.tsx @@ -141,7 +141,12 @@ const Card = ({ {/* Action Button */}
- + {button.icon} {button.label} diff --git a/frontend/src/components/GeneralCompliantComponent.tsx b/frontend/src/components/GeneralCompliantComponent.tsx index c7cdfaf0ad..2d87386319 100644 --- a/frontend/src/components/GeneralCompliantComponent.tsx +++ b/frontend/src/components/GeneralCompliantComponent.tsx @@ -4,7 +4,6 @@ import { Tooltip } from '@heroui/tooltip' import clsx from 'clsx' import { FC } from 'react' import type { IconType } from 'react-icons' -import { FaCertificate } from 'react-icons/fa6' import { IconWrapper } from 'wrappers/IconWrapper' const GeneralCompliantComponent: FC<{ @@ -14,24 +13,16 @@ const GeneralCompliantComponent: FC<{ }> = ({ icon, compliant, title }) => { return ( -
- - +
+
) diff --git a/frontend/src/components/ModuleCard.tsx b/frontend/src/components/ModuleCard.tsx index 5837b098a4..87de94edf9 100644 --- a/frontend/src/components/ModuleCard.tsx +++ b/frontend/src/components/ModuleCard.tsx @@ -1,6 +1,7 @@ import upperFirst from 'lodash/upperFirst' import Link from 'next/link' import { usePathname } from 'next/navigation' +import type React from 'react' import { useState } from 'react' import { FaChevronDown, FaChevronUp, FaTurnUp, FaCalendar, FaHourglassHalf } from 'react-icons/fa6' import type { Module } from 'types/mentorship' @@ -26,6 +27,13 @@ const ModuleCard = ({ modules, accessLevel, admins }: ModuleCardProps) => { const displayedModule = showAllModule ? modules : modules.slice(0, 4) const isAdmin = accessLevel === 'admin' + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + setShowAllModule(!showAllModule) + } + } + return (
@@ -38,7 +46,8 @@ const ModuleCard = ({ modules, accessLevel, admins }: ModuleCardProps) => {
) : ( diff --git a/frontend/src/components/Search.tsx b/frontend/src/components/Search.tsx index 1cdd7b75ea..7848aa4d80 100644 --- a/frontend/src/components/Search.tsx +++ b/frontend/src/components/Search.tsx @@ -66,6 +66,13 @@ const SearchBar: React.FC = ({ inputRef.current?.focus() } + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + handleClearSearch() + } + } + return (
@@ -89,6 +96,7 @@ const SearchBar: React.FC = ({ type="button" className="absolute top-1/2 right-2 h-8 w-8 -translate-y-1/2 rounded-md p-1 text-gray-400 hover:bg-gray-400 hover:text-gray-200 focus:ring-2 focus:ring-gray-300 focus:outline-hidden dark:hover:bg-gray-600" onClick={handleClearSearch} + onKeyDown={handleKeyDown} aria-label="Clear search" >