From 291d9d09fb64b3894654dd8e6b7b26774c8a40fd Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 4 Jun 2026 16:13:49 +0300 Subject: [PATCH 01/11] fix(packages): upgraded angular packages to fix ssr critical issue --- package-lock.json | 226 +++++++++++++++++++++++----------------------- package.json | 24 ++--- 2 files changed, 125 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac558ab70..f58f5579d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,16 +8,16 @@ "name": "osf", "version": "26.9.1", "dependencies": { - "@angular/animations": "^21.2.7", + "@angular/animations": "^21.2.16", "@angular/cdk": "^21.2.6", - "@angular/common": "^21.2.7", - "@angular/compiler": "^21.2.7", - "@angular/core": "^21.2.7", - "@angular/forms": "^21.2.7", - "@angular/platform-browser": "^21.2.7", - "@angular/platform-browser-dynamic": "^21.2.7", - "@angular/platform-server": "^21.2.7", - "@angular/router": "^21.2.7", + "@angular/common": "^21.2.16", + "@angular/compiler": "^21.2.16", + "@angular/core": "^21.2.16", + "@angular/forms": "^21.2.16", + "@angular/platform-browser": "^21.2.16", + "@angular/platform-browser-dynamic": "^21.2.16", + "@angular/platform-server": "^21.2.16", + "@angular/router": "^21.2.16", "@angular/ssr": "^21.2.7", "@centerforopenscience/markdown-it-atrules": "^0.1.2", "@citation-js/core": "^0.7.21", @@ -55,9 +55,9 @@ "@angular-eslint/eslint-plugin": "^21.3.0", "@angular-eslint/eslint-plugin-template": "^21.3.0", "@angular-eslint/template-parser": "^21.3.0", - "@angular/build": "^21.2.7", - "@angular/cli": "^21.2.7", - "@angular/compiler-cli": "^21.2.7", + "@angular/build": "^21.2.14", + "@angular/cli": "^21.2.14", + "@angular/compiler-cli": "^21.2.16", "@commitlint/cli": "^20.4.3", "@commitlint/config-conventional": "^20.4.3", "@eslint/js": "^10.0.1", @@ -316,13 +316,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.7.tgz", - "integrity": "sha512-4K/5hln9iaPEt3F/NyYqncNLvYpzSjRslEkHl2xIgZwQsIFHEvhnDRBYj2/oatURQhBqO/Yu15z/icVOYLxuTg==", + "version": "0.2102.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.14.tgz", + "integrity": "sha512-0+vjVsCkMyJdVjz5XkPW+Bdf/9TI8V2voomx/+o0o+oOaqqiEhptQWFnaIlLr7HasjB0LxXK5P9L0oQ61vxj8Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.7", + "@angular-devkit/core": "21.2.14", "rxjs": "7.8.2" }, "bin": { @@ -335,9 +335,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.7.tgz", - "integrity": "sha512-DONYY5u4IENO2qpd23mODaE4JI2EIohWV1kuJnsU9HIcm5wN714QB2z9WY/s4gLfUiAMIUu/8lpnW/0kOQZAnQ==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.14.tgz", + "integrity": "sha512-RSOWXB9bFc2nwRWMxbIT0RbSNFUrwfBo4N5MNxbyQ69Ndc0gVm3h+3ArHv0qotH4d+pJYbm5ttXu8YqR2kc0CA==", "dev": true, "license": "MIT", "dependencies": { @@ -363,13 +363,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.7.tgz", - "integrity": "sha512-LYAjjUI1qM7pR/sd0yYt8OLA6ljOOXjcfzV40I5XQNmhAxq90YYS5xwMcixOmWX+z5zvCYGvPXvJGWjzio6SUg==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.14.tgz", + "integrity": "sha512-KMJlQSBEzI4+Cy1Zh72gmGQNN2I1vY+nj9CoRcZPBIi1si+0ZAc49XT85eYl+eQumNTVQviUG7LQqgLDAHml+g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.7", + "@angular-devkit/core": "21.2.14", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", "ora": "9.3.0", @@ -491,9 +491,9 @@ } }, "node_modules/@angular/animations": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.9.tgz", - "integrity": "sha512-wOWbrneivpTYx3xhiPygoNFNC8ZZ1shpgwBe1hYvfky1fkiz1c92XeHIW1V4rPqYw6d3U55aUX5InyTsVe2Xng==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.16.tgz", + "integrity": "sha512-YPhph/OC1A0vkT95XZW6lXMNmi5ly91JeXi+5yeG8CCxfqscVfRNPsYbRWjSueO0cQT2HJ8U1CLteQ5a1OaoHA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -502,18 +502,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.9" + "@angular/core": "21.2.16" } }, "node_modules/@angular/build": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.7.tgz", - "integrity": "sha512-FpSkFqpsJtdN1cROekVYkmeV1QepdP+/d7fyYQEuNmlOlyqXSDh9qJmy4iL9VNbAU0rk+vFCtYM86rO7Pt9cSw==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.14.tgz", + "integrity": "sha512-l8JB326iIwum2WmbopUUFdiuYsbHchix6MH8o6F6FA7LJr8QLTvipwwbw+Jx31/RE50WkGmzsZ1fBDw/cMbmUw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.7", + "@angular-devkit/architect": "0.2102.14", "@babel/core": "7.29.0", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -556,7 +556,7 @@ "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.7", + "@angular/ssr": "^21.2.14", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", @@ -622,19 +622,19 @@ } }, "node_modules/@angular/cli": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.7.tgz", - "integrity": "sha512-N/wj8fFRB718efIFYpwnYfy+MecZREZXsUNMTVndFLH6T0jCheb9PVetR6jsyZp6h46USNPOmJYJ/9255lME+Q==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.14.tgz", + "integrity": "sha512-S8jExTjxPJILwpg2lu3DohSASVZ8DLhSNCmOe7z0qF9VskRSjC7SIQv1rq36tsJkenxuA72gjVOHZv+uSRT8HA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.7", - "@angular-devkit/core": "21.2.7", - "@angular-devkit/schematics": "21.2.7", + "@angular-devkit/architect": "0.2102.14", + "@angular-devkit/core": "21.2.14", + "@angular-devkit/schematics": "21.2.14", "@inquirer/prompts": "7.10.1", "@listr2/prompt-adapter-inquirer": "3.0.5", "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.7", + "@schematics/angular": "21.2.14", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.48.1", "ini": "6.0.0", @@ -657,9 +657,9 @@ } }, "node_modules/@angular/common": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.9.tgz", - "integrity": "sha512-7spQcF3hPN/fjTx6Pwa32KRRdO0NcixnRuPV4lo50ejtXesjiLVR+fkaX38sawAyGoq89IuuYvUDrbLwCMypmQ==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.16.tgz", + "integrity": "sha512-htHNepKzjIjkc5BQ7MKDN0bVDOfQpFr/fGUxa6irC0kFLfWt7idUTdNcxypRvjCCTuBYHkjr74fH4QKu+qvPXg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -668,14 +668,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.9", + "@angular/core": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.9.tgz", - "integrity": "sha512-clsK1EsSPtAuqlRl4CciA/gsvsW7xe0eWcvHxtrMW6DYaUJ6X4AAuDxEEJ5cf/3Mpw4s8KssjIUPPtbrUIGLSQ==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.16.tgz", + "integrity": "sha512-hVjp93gYgNj5aRbCQUK7L+pOfdqk96lCtmSL2hOL725Pmib9NyNIrA3ISfAQHN+Qo70763WUZahOiqBBOzfAcg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -685,9 +685,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.9.tgz", - "integrity": "sha512-hTTW/OiqTXrwTneS18CMp47OX0XSbLYl2rIomLS3nXVJniSETH6S/k+LqQtGWWgLbzsd3PzUOOckHnvzpTBTsA==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.16.tgz", + "integrity": "sha512-w2ck3o+uw29AZEGK3HvOsF/ZRiPcfoq2TaDtiNjdH+svhwawt9PfMXrDbbIKF30prWzKLpT3UsCqTz1awv7Ubw==", "dev": true, "license": "MIT", "dependencies": { @@ -708,7 +708,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.9", + "@angular/compiler": "21.2.16", "typescript": ">=5.9 <6.1" }, "peerDependenciesMeta": { @@ -718,9 +718,9 @@ } }, "node_modules/@angular/core": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.9.tgz", - "integrity": "sha512-uZLq2aedJ+0uEZxyf6a1Nc7y1aZ7akAW7K1Kon8JUDZOvI2IDbk0i00MzkELt8q9uSmSSqg9zNKuhjspFf0Pyw==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.16.tgz", + "integrity": "sha512-uufKORlB0jeYdqOvjAfMYgqIqmJentOj8XvTUxsFP5k85xxzXsDarSpP199YQz6jhJJQYNOWIloDkUTQJi5rNA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -729,7 +729,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.9", + "@angular/compiler": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -743,9 +743,9 @@ } }, "node_modules/@angular/forms": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.9.tgz", - "integrity": "sha512-qXLnzmsJoHMgV/gDU7AZgsKBhUH7k6im6V9YuY5UpHHl+nGKCWxtePAZRB0OH2AsqzLwER3Fv2S6+mtmb7651w==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.16.tgz", + "integrity": "sha512-2djTJmTpg/MkQ2kdCI9k0LT4RL9/Hg03fDUNN2eN5c04FIk99D3yHXUJYLwiaErLuLQNkU8HaijluKHdH93cWQ==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -755,16 +755,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.9", - "@angular/core": "21.2.9", - "@angular/platform-browser": "21.2.9", + "@angular/common": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.9.tgz", - "integrity": "sha512-MjEtFvoFtsjsAeu2yzauqGgwwEHV4ml25c9vGFmw4OmSoNme4yp41f2DegwOkn1TTHL3OF3GE65ng2U2feJU4Q==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.16.tgz", + "integrity": "sha512-59ToWYDb+O3fS0+Y4ubQqV0zY6sf2esLZ19AT7JKXN7Akqbz7aQ2/3k3PKmfhwKWek5o3lkuNz8YhxKQruNh8Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -773,9 +773,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "21.2.9", - "@angular/common": "21.2.9", - "@angular/core": "21.2.9" + "@angular/animations": "21.2.16", + "@angular/common": "21.2.16", + "@angular/core": "21.2.16" }, "peerDependenciesMeta": { "@angular/animations": { @@ -784,9 +784,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.9.tgz", - "integrity": "sha512-Z+2vefW4GUSuTC4BOKNiyftqecLSjxOKwe1ZNljBsjesLzywIXi+v+tyEm8ODHHlf7bz/0HwXvc9OYZmfjt95A==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.16.tgz", + "integrity": "sha512-WtTnkJOmKiGccHRQfBdkwODAkpTB4zbPN3IKhcqCjlezKaPqZB5tjrIu72Z5pmi5VIgJz1LmfO1LSVCMC5h7dA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -795,16 +795,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.9", - "@angular/compiler": "21.2.9", - "@angular/core": "21.2.9", - "@angular/platform-browser": "21.2.9" + "@angular/common": "21.2.16", + "@angular/compiler": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16" } }, "node_modules/@angular/platform-server": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-21.2.9.tgz", - "integrity": "sha512-sVkx1762qO+XDE+JFnMZU/m95W2v+Qg5Kh1IIQ9wG9krjV2Tl6ufnGYdxKf4EKnPj7oOQdhKq4cb8VhOokESBw==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-21.2.16.tgz", + "integrity": "sha512-PealRRIEFkwzlc9sjYg5/gjq2l7Mn/lPQgUPryqP5y4x38uC6gg2dPtnQTlUietY7YDcKn5HJ04GFYiQE6011Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0", @@ -814,17 +814,17 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.9", - "@angular/compiler": "21.2.9", - "@angular/core": "21.2.9", - "@angular/platform-browser": "21.2.9", + "@angular/common": "21.2.16", + "@angular/compiler": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/router": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.9.tgz", - "integrity": "sha512-ExqOEO6IUuNaI75ZcjAbOuzJKpvVze6hRdETyVf7Sny07+XSKv9t8DK9tBHmR7+67wz+zPIUgCXxsQXi8jJu0w==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.16.tgz", + "integrity": "sha512-0+Pyh0uT4vCLabKoGCARYWlwpz4DgZI9AE01n8s9u/nKAZuEMnJtLLnaUtHEMI8nJSqpgnS/5AthuJZdDEfkYw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -833,16 +833,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.9", - "@angular/core": "21.2.9", - "@angular/platform-browser": "21.2.9", + "@angular/common": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/ssr": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-21.2.7.tgz", - "integrity": "sha512-NhrkeD32s3H/jU9yJLqDy2JBNNatFyzqNkwieJw0waEvBRNbxXlcg5+g6rilcg2nHlH5hyzMQUzs7ZwZH9wCqg==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-21.2.14.tgz", + "integrity": "sha512-f7raowG4+dcHTbqeftdJwzwiEuAig9qj67ID+cXMQ3nCcPYzJ/eZwRlAeU43ZUH2eznnA2plhnn86wU32BY6cA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -4955,14 +4955,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.2.7", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.7.tgz", - "integrity": "sha512-aqEj3RyBtmH+41HZvrbfrpCo0e+0NzwyQyNSC/wLDShVqoidBtPbEdHU1FZ4+ni41da7rI3F12gUuAHws27kMA==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.14.tgz", + "integrity": "sha512-rIEdtNTdCCTwuo7B4tMoq5qmbLXdBgmW6Ays1hyno//4OE+HFtvlWZd+hl6KceEyN00IcZ2HRaPnfd71E1JnoA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.7", - "@angular-devkit/schematics": "21.2.7", + "@angular-devkit/core": "21.2.14", + "@angular-devkit/schematics": "21.2.14", "jsonc-parser": "3.3.1" }, "engines": { @@ -6238,9 +6238,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -7726,13 +7726,13 @@ } }, "node_modules/express-rate-limit": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", - "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "10.1.0" + "ip-address": "^10.2.0" }, "engines": { "node": ">= 16" @@ -7794,9 +7794,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -8227,9 +8227,9 @@ } }, "node_modules/hono": { - "version": "4.12.14", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz", - "integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==", + "version": "4.12.23", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", + "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "dev": true, "license": "MIT", "engines": { @@ -8526,9 +8526,9 @@ } }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -10878,9 +10878,9 @@ } }, "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" diff --git a/package.json b/package.json index 3409621d3..774424b8c 100644 --- a/package.json +++ b/package.json @@ -31,16 +31,16 @@ }, "private": true, "dependencies": { - "@angular/animations": "^21.2.7", + "@angular/animations": "^21.2.16", "@angular/cdk": "^21.2.6", - "@angular/common": "^21.2.7", - "@angular/compiler": "^21.2.7", - "@angular/core": "^21.2.7", - "@angular/forms": "^21.2.7", - "@angular/platform-browser": "^21.2.7", - "@angular/platform-browser-dynamic": "^21.2.7", - "@angular/platform-server": "^21.2.7", - "@angular/router": "^21.2.7", + "@angular/common": "^21.2.16", + "@angular/compiler": "^21.2.16", + "@angular/core": "^21.2.16", + "@angular/forms": "^21.2.16", + "@angular/platform-browser": "^21.2.16", + "@angular/platform-browser-dynamic": "^21.2.16", + "@angular/platform-server": "^21.2.16", + "@angular/router": "^21.2.16", "@angular/ssr": "^21.2.7", "@centerforopenscience/markdown-it-atrules": "^0.1.2", "@citation-js/core": "^0.7.21", @@ -78,9 +78,9 @@ "@angular-eslint/eslint-plugin": "^21.3.0", "@angular-eslint/eslint-plugin-template": "^21.3.0", "@angular-eslint/template-parser": "^21.3.0", - "@angular/build": "^21.2.7", - "@angular/cli": "^21.2.7", - "@angular/compiler-cli": "^21.2.7", + "@angular/build": "^21.2.14", + "@angular/cli": "^21.2.14", + "@angular/compiler-cli": "^21.2.16", "@commitlint/cli": "^20.4.3", "@commitlint/config-conventional": "^20.4.3", "@eslint/js": "^10.0.1", From 34bf45de33ed5ddccfcd15e9b7d1fc7d8ef5cbc1 Mon Sep 17 00:00:00 2001 From: nsemets Date: Wed, 17 Jun 2026 10:57:31 +0300 Subject: [PATCH 02/11] fix(vulnerabilities): fixed some issues --- package-lock.json | 62 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index f8dc1df3b..4008f2269 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8227,9 +8227,9 @@ } }, "node_modules/hono": { - "version": "4.12.23", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", - "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", + "version": "4.12.25", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", + "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", "dev": true, "license": "MIT", "engines": { @@ -8790,10 +8790,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -8991,9 +9001,19 @@ "license": "MIT" }, "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" @@ -9348,14 +9368,24 @@ } }, "node_modules/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", - "linkify-it": "^5.0.0", + "linkify-it": "^5.0.1", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" @@ -11967,9 +11997,9 @@ } }, "node_modules/tar": { - "version": "7.5.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", - "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "version": "7.5.16", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", + "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { From b43bab5e7f8427a8b0d04c5effa78042eee92fc9 Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 2 Jul 2026 10:26:13 +0300 Subject: [PATCH 03/11] fix(package): updated packages versions to fix issues --- package-lock.json | 1338 +++++++++++++++++++++++---------------------- package.json | 36 +- 2 files changed, 688 insertions(+), 686 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4008f2269..8b357d9d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,17 +8,17 @@ "name": "osf", "version": "26.10.1", "dependencies": { - "@angular/animations": "^21.2.16", - "@angular/cdk": "^21.2.6", - "@angular/common": "^21.2.16", - "@angular/compiler": "^21.2.16", - "@angular/core": "^21.2.16", - "@angular/forms": "^21.2.16", - "@angular/platform-browser": "^21.2.16", - "@angular/platform-browser-dynamic": "^21.2.16", - "@angular/platform-server": "^21.2.16", - "@angular/router": "^21.2.16", - "@angular/ssr": "^21.2.7", + "@angular/animations": "^21.2.17", + "@angular/cdk": "^21.2.14", + "@angular/common": "^21.2.17", + "@angular/compiler": "^21.2.17", + "@angular/core": "^21.2.17", + "@angular/forms": "^21.2.17", + "@angular/platform-browser": "^21.2.17", + "@angular/platform-browser-dynamic": "^21.2.17", + "@angular/platform-server": "^21.2.17", + "@angular/router": "^21.2.17", + "@angular/ssr": "^21.2.18", "@centerforopenscience/markdown-it-atrules": "^0.1.2", "@citation-js/core": "^0.7.21", "@citation-js/plugin-csl": "^0.7.21", @@ -55,9 +55,9 @@ "@angular-eslint/eslint-plugin": "^21.3.0", "@angular-eslint/eslint-plugin-template": "^21.3.0", "@angular-eslint/template-parser": "^21.3.0", - "@angular/build": "^21.2.14", - "@angular/cli": "^21.2.14", - "@angular/compiler-cli": "^21.2.16", + "@angular/build": "^21.2.18", + "@angular/cli": "^21.2.18", + "@angular/compiler-cli": "^21.2.17", "@commitlint/cli": "^20.4.3", "@commitlint/config-conventional": "^20.4.3", "@eslint/js": "^10.0.1", @@ -66,7 +66,7 @@ "@types/gapi.auth2": "^0.0.61", "@types/markdown-it": "^14.1.2", "@types/node": "^20.17.19", - "@vitest/coverage-v8": "^4.1.1", + "@vitest/coverage-v8": "^4.1.9", "angular-eslint": "^21.3.0", "angularx-qrcode": "^21.0.4", "eslint": "^10.0.2", @@ -75,23 +75,16 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unused-imports": "^4.4.1", "husky": "^9.1.7", - "jsdom": "^28.0.0", + "jsdom": "^29.1.1", "lint-staged": "^16.3.2", - "ng-mocks": "^14.15.1", + "ng-mocks": "^14.15.3", "prettier": "3.8.1", "source-map-explorer": "^2.5.3", "typescript": "~5.9.3", "typescript-eslint": "^8.56.1", - "vitest": "^4.1.1" + "vitest": "^4.1.9" } }, - "node_modules/@acemir/cssom": { - "version": "0.9.31", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", - "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", - "dev": true, - "license": "MIT" - }, "node_modules/@algolia/abtesting": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.1.tgz", @@ -316,13 +309,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.14.tgz", - "integrity": "sha512-0+vjVsCkMyJdVjz5XkPW+Bdf/9TI8V2voomx/+o0o+oOaqqiEhptQWFnaIlLr7HasjB0LxXK5P9L0oQ61vxj8Q==", + "version": "0.2102.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.18.tgz", + "integrity": "sha512-bEkF4ApWa6FJ2+ZyFPdhQr05PgJv/oKwx+3goNRa4lSxzJO+O3KXr0ivTyE5zEJ8l4JdV3h93bsCP54Rk3v7Dw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.14", + "@angular-devkit/core": "21.2.18", "rxjs": "7.8.2" }, "bin": { @@ -335,9 +328,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.14.tgz", - "integrity": "sha512-RSOWXB9bFc2nwRWMxbIT0RbSNFUrwfBo4N5MNxbyQ69Ndc0gVm3h+3ArHv0qotH4d+pJYbm5ttXu8YqR2kc0CA==", + "version": "21.2.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.18.tgz", + "integrity": "sha512-783AuDmzAjFkOBHey7cx1mXd8CTiMg9LvG+BCxEp8i4EB7cOGYrq3lBzkwhKJq6yYpz7dNgM1QgeLk+NcrFBSA==", "dev": true, "license": "MIT", "dependencies": { @@ -363,13 +356,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.14.tgz", - "integrity": "sha512-KMJlQSBEzI4+Cy1Zh72gmGQNN2I1vY+nj9CoRcZPBIi1si+0ZAc49XT85eYl+eQumNTVQviUG7LQqgLDAHml+g==", + "version": "21.2.18", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.18.tgz", + "integrity": "sha512-PakHs+Eefx06KORDFyH4wmkIZ/wm4mI4DqhXe4XFuWJOazMQoYJxPmMeby47BD0HhvJN7BskN61CPS8HCAvICg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.14", + "@angular-devkit/core": "21.2.18", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", "ora": "9.3.0", @@ -491,9 +484,10 @@ } }, "node_modules/@angular/animations": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.16.tgz", - "integrity": "sha512-YPhph/OC1A0vkT95XZW6lXMNmi5ly91JeXi+5yeG8CCxfqscVfRNPsYbRWjSueO0cQT2HJ8U1CLteQ5a1OaoHA==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.17.tgz", + "integrity": "sha512-zOW8FFa9qfbVkZ5TulxDkl1C3+gEjWfAAD5Z2MycA6pjVJQlLYPiTAGq+flOQ3yZfTT0z6kd5rejQMXWI81Dvg==", + "deprecated": "@angular/animations is deprecated. Use `animate.enter` and `animate.leave` instead. For more information see: https://v22.angular.dev/guide/animations.", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -502,26 +496,26 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.16" + "@angular/core": "21.2.17" } }, "node_modules/@angular/build": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.14.tgz", - "integrity": "sha512-l8JB326iIwum2WmbopUUFdiuYsbHchix6MH8o6F6FA7LJr8QLTvipwwbw+Jx31/RE50WkGmzsZ1fBDw/cMbmUw==", + "version": "21.2.18", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.18.tgz", + "integrity": "sha512-9Jic0Dud6d0ULPR5SceHV86AzZE42cNWPsbLKrK1dUneaAC44GSVRTmLXcaSX/5Exa3gGjFANQw4qashgxUekQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.14", - "@babel/core": "7.29.0", + "@angular-devkit/architect": "0.2102.18", + "@babel/core": "7.29.7", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", "@inquirer/confirm": "5.1.21", "@vitejs/plugin-basic-ssl": "2.1.4", "beasties": "0.4.1", "browserslist": "^4.26.0", - "esbuild": "0.27.3", + "esbuild": "0.28.1", "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", @@ -530,14 +524,14 @@ "mrmime": "2.0.1", "parse5-html-rewriting-stream": "8.0.0", "picomatch": "4.0.4", - "piscina": "5.1.4", + "piscina": "5.2.0", "rolldown": "1.0.0-rc.4", "sass": "1.97.3", "semver": "7.7.4", "source-map-support": "0.5.21", "tinyglobby": "0.2.15", - "undici": "7.24.4", - "vite": "7.3.2", + "undici": "7.28.0", + "vite": "7.3.6", "watchpack": "2.5.1" }, "engines": { @@ -556,7 +550,7 @@ "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.14", + "@angular/ssr": "^21.2.18", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", @@ -606,9 +600,9 @@ } }, "node_modules/@angular/cdk": { - "version": "21.2.6", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.6.tgz", - "integrity": "sha512-1PBzFf+um/VZ1dFF6cT72Zsq+9C/ZWF9m5dP0uHJgo4psX3yMBoZlZu5YomBiAQ/ePSkqCuryv1vrelK+yd3Mw==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.14.tgz", + "integrity": "sha512-806REq/CLf37nEhmmd8Q+ILN8z/RVG2vk2n8YZ/4TdHpcBCi5ux4AxLbpMmduLwGPOzPagJ6ggRzE5fnX0rmcQ==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", @@ -622,26 +616,26 @@ } }, "node_modules/@angular/cli": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.14.tgz", - "integrity": "sha512-S8jExTjxPJILwpg2lu3DohSASVZ8DLhSNCmOe7z0qF9VskRSjC7SIQv1rq36tsJkenxuA72gjVOHZv+uSRT8HA==", + "version": "21.2.18", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.18.tgz", + "integrity": "sha512-WOZF4p0SnrmBpNeiOA2pdp9OBvGnOSLWbGdRLXJykyseIiEn7+N+GZp+ZA1aNZB4SWolpYCZfTYwkpo6Sf/LXg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.14", - "@angular-devkit/core": "21.2.14", - "@angular-devkit/schematics": "21.2.14", + "@angular-devkit/architect": "0.2102.18", + "@angular-devkit/core": "21.2.18", + "@angular-devkit/schematics": "21.2.18", "@inquirer/prompts": "7.10.1", "@listr2/prompt-adapter-inquirer": "3.0.5", "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.14", + "@schematics/angular": "21.2.18", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.48.1", "ini": "6.0.0", "jsonc-parser": "3.3.1", "listr2": "9.0.5", "npm-package-arg": "13.0.2", - "pacote": "21.3.1", + "pacote": "21.5.1", "parse5-html-rewriting-stream": "8.0.0", "semver": "7.7.4", "yargs": "18.0.0", @@ -657,9 +651,9 @@ } }, "node_modules/@angular/common": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.16.tgz", - "integrity": "sha512-htHNepKzjIjkc5BQ7MKDN0bVDOfQpFr/fGUxa6irC0kFLfWt7idUTdNcxypRvjCCTuBYHkjr74fH4QKu+qvPXg==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.17.tgz", + "integrity": "sha512-hqAQxRfi5ldFE42suAXRcY+JCANrUh7fuSQ/DtZ7L896id5BT/exuv6dWNBC1PyAfQmRbpD5Pt6/pd+tNLyhDQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -668,14 +662,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.16", + "@angular/core": "21.2.17", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.16.tgz", - "integrity": "sha512-hVjp93gYgNj5aRbCQUK7L+pOfdqk96lCtmSL2hOL725Pmib9NyNIrA3ISfAQHN+Qo70763WUZahOiqBBOzfAcg==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.17.tgz", + "integrity": "sha512-p+NdjYiwAz9Zmu2yul0LlMXaFjMISVVa24+/MVMoKFeQeI82QE8jDywPlnOSHQHvdCcQVpS7saeEriZzX3JuBQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -685,9 +679,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.16.tgz", - "integrity": "sha512-w2ck3o+uw29AZEGK3HvOsF/ZRiPcfoq2TaDtiNjdH+svhwawt9PfMXrDbbIKF30prWzKLpT3UsCqTz1awv7Ubw==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.17.tgz", + "integrity": "sha512-KithZ3b0HBFH0NbUcswBcjpN9y09vLbarMD7qmGWTnGUBk4W8cn4sbT8zJyv9CRKg9ZcuUBeJYKUfUPn/u/5OQ==", "dev": true, "license": "MIT", "dependencies": { @@ -708,7 +702,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.16", + "@angular/compiler": "21.2.17", "typescript": ">=5.9 <6.1" }, "peerDependenciesMeta": { @@ -717,10 +711,58 @@ } } }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@angular/core": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.16.tgz", - "integrity": "sha512-uufKORlB0jeYdqOvjAfMYgqIqmJentOj8XvTUxsFP5k85xxzXsDarSpP199YQz6jhJJQYNOWIloDkUTQJi5rNA==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.17.tgz", + "integrity": "sha512-wYHpwIdnUnjQFOJJNqRcGx7LS3u64jT+R9L0TnMR/ViBM9dQgGYImlSikkftg2yrFCNo5aKRxhG2LLskQurVdg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -729,7 +771,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.16", + "@angular/compiler": "21.2.17", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -743,9 +785,9 @@ } }, "node_modules/@angular/forms": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.16.tgz", - "integrity": "sha512-2djTJmTpg/MkQ2kdCI9k0LT4RL9/Hg03fDUNN2eN5c04FIk99D3yHXUJYLwiaErLuLQNkU8HaijluKHdH93cWQ==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.17.tgz", + "integrity": "sha512-WKu8XeRSNZo+a+aDDZ3M5OtReF7KYqR/PmZ2l1lSf6N5EEAmc+Ky4aqbRhTL/mTSfHrO4+TDJ4C5A2tFmuwIeA==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -755,16 +797,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.16", - "@angular/core": "21.2.16", - "@angular/platform-browser": "21.2.16", + "@angular/common": "21.2.17", + "@angular/core": "21.2.17", + "@angular/platform-browser": "21.2.17", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.16.tgz", - "integrity": "sha512-59ToWYDb+O3fS0+Y4ubQqV0zY6sf2esLZ19AT7JKXN7Akqbz7aQ2/3k3PKmfhwKWek5o3lkuNz8YhxKQruNh8Q==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.17.tgz", + "integrity": "sha512-ROdSliejY37g1EphYmweYdm5cHM8HY3X4tbWt4ubxmhTyYgfN3nxrxfGQ/n7Mz5tDY9VXVLIGDgjLOGYOo4uTQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -773,9 +815,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "21.2.16", - "@angular/common": "21.2.16", - "@angular/core": "21.2.16" + "@angular/animations": "21.2.17", + "@angular/common": "21.2.17", + "@angular/core": "21.2.17" }, "peerDependenciesMeta": { "@angular/animations": { @@ -784,9 +826,10 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.16.tgz", - "integrity": "sha512-WtTnkJOmKiGccHRQfBdkwODAkpTB4zbPN3IKhcqCjlezKaPqZB5tjrIu72Z5pmi5VIgJz1LmfO1LSVCMC5h7dA==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.17.tgz", + "integrity": "sha512-r/BU/T8bOTghP3fIXhzYf5wcMcAmhWnAFv3p4asCCPXomaktoas70wYcMaDH+pK1LAFBxLwzBWHm36MpFlTMFg==", + "deprecated": "@angular/platform-browser-dynamic is deprecated. Use `@angular/platform-browser` instead.", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -795,16 +838,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.16", - "@angular/compiler": "21.2.16", - "@angular/core": "21.2.16", - "@angular/platform-browser": "21.2.16" + "@angular/common": "21.2.17", + "@angular/compiler": "21.2.17", + "@angular/core": "21.2.17", + "@angular/platform-browser": "21.2.17" } }, "node_modules/@angular/platform-server": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-21.2.16.tgz", - "integrity": "sha512-PealRRIEFkwzlc9sjYg5/gjq2l7Mn/lPQgUPryqP5y4x38uC6gg2dPtnQTlUietY7YDcKn5HJ04GFYiQE6011Q==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-21.2.17.tgz", + "integrity": "sha512-ll5mbZHyUjZp+aL5eFCcusZBMLYv2fbxuPAIhAHFpu55kC9zh7PFlbdINbr4kT/bjxYb4isw5nDbGj9+n+RHWg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0", @@ -814,17 +857,17 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.16", - "@angular/compiler": "21.2.16", - "@angular/core": "21.2.16", - "@angular/platform-browser": "21.2.16", + "@angular/common": "21.2.17", + "@angular/compiler": "21.2.17", + "@angular/core": "21.2.17", + "@angular/platform-browser": "21.2.17", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/router": { - "version": "21.2.16", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.16.tgz", - "integrity": "sha512-0+Pyh0uT4vCLabKoGCARYWlwpz4DgZI9AE01n8s9u/nKAZuEMnJtLLnaUtHEMI8nJSqpgnS/5AthuJZdDEfkYw==", + "version": "21.2.17", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.17.tgz", + "integrity": "sha512-RSCtK5ppAV6y6wfRLHSK2a9Wc/vm8j0wsC+/j9PH9yQmppWFVXDWsg5E39MKOIpnoYVx2+hI6eak6+wYtZTe1A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -833,16 +876,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.16", - "@angular/core": "21.2.16", - "@angular/platform-browser": "21.2.16", + "@angular/common": "21.2.17", + "@angular/core": "21.2.17", + "@angular/platform-browser": "21.2.17", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/ssr": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-21.2.14.tgz", - "integrity": "sha512-f7raowG4+dcHTbqeftdJwzwiEuAig9qj67ID+cXMQ3nCcPYzJ/eZwRlAeU43ZUH2eznnA2plhnn86wU32BY6cA==", + "version": "21.2.18", + "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-21.2.18.tgz", + "integrity": "sha512-XLCMFm8/1ElMIlXe2idelA6hAHIvrbuTGQYm1c/Vz4CSkMilTb4hnZimU7CaoQdvvSjf2g9xj+QxmEW+eGDUSw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -877,27 +920,20 @@ } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", - "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", "dev": true, "license": "MIT", "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", - "css-tree": "^3.1.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.6" - } - }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", - "dev": true, - "license": "BlueOak-1.0.0", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/generational-cache": { @@ -918,13 +954,13 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -933,9 +969,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -943,21 +979,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -991,14 +1027,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -1021,14 +1057,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -1048,9 +1084,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -1058,29 +1094,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1103,9 +1139,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -1113,9 +1149,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -1123,9 +1159,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -1133,27 +1169,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1163,33 +1199,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -1197,14 +1233,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1698,9 +1734,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", - "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", "dev": true, "funding": [ { @@ -1718,9 +1754,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz", - "integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", "dev": true, "funding": [ { @@ -1742,9 +1778,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz", - "integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.9.tgz", + "integrity": "sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==", "dev": true, "funding": [ { @@ -1758,8 +1794,8 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.2.0" + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.2.1" }, "engines": { "node": ">=20.19.0" @@ -1793,9 +1829,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", - "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz", + "integrity": "sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==", "dev": true, "funding": [ { @@ -1838,22 +1874,22 @@ } }, "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "dev": true, "license": "MIT", "optional": true, "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.1", + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "dev": true, "license": "MIT", "optional": true, @@ -1863,9 +1899,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -1875,9 +1911,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -1892,9 +1928,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -1909,9 +1945,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -1926,9 +1962,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -1943,9 +1979,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -1960,9 +1996,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -1977,9 +2013,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -1994,9 +2030,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -2011,9 +2047,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -2028,9 +2064,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -2045,9 +2081,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -2062,9 +2098,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -2079,9 +2115,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -2096,9 +2132,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -2113,9 +2149,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -2130,9 +2166,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -2147,9 +2183,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -2164,9 +2200,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -2181,9 +2217,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -2198,9 +2234,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -2215,9 +2251,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -2232,9 +2268,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -2249,9 +2285,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -2266,9 +2302,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -2283,9 +2319,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -2300,9 +2336,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -3697,9 +3733,9 @@ } }, "node_modules/@npmcli/agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", - "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.2.tgz", + "integrity": "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg==", "dev": true, "license": "ISC", "dependencies": { @@ -3714,9 +3750,9 @@ } }, "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -3767,9 +3803,9 @@ } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -4566,9 +4602,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", - "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", "cpu": [ "arm" ], @@ -4580,9 +4616,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", - "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", "cpu": [ "arm64" ], @@ -4594,9 +4630,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", - "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", "cpu": [ "arm64" ], @@ -4608,9 +4644,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", - "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", "cpu": [ "x64" ], @@ -4622,9 +4658,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", - "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", "cpu": [ "arm64" ], @@ -4636,9 +4672,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", - "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", "cpu": [ "x64" ], @@ -4650,9 +4686,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", - "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", "cpu": [ "arm" ], @@ -4667,9 +4703,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", - "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", "cpu": [ "arm" ], @@ -4684,9 +4720,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", - "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", "cpu": [ "arm64" ], @@ -4701,9 +4737,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", - "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", "cpu": [ "arm64" ], @@ -4718,9 +4754,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", - "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", "cpu": [ "loong64" ], @@ -4735,9 +4771,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", - "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", "cpu": [ "loong64" ], @@ -4752,9 +4788,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", - "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", "cpu": [ "ppc64" ], @@ -4769,9 +4805,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", - "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", "cpu": [ "ppc64" ], @@ -4786,9 +4822,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", - "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", "cpu": [ "riscv64" ], @@ -4803,9 +4839,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", - "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", "cpu": [ "riscv64" ], @@ -4820,9 +4856,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", - "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", "cpu": [ "s390x" ], @@ -4837,9 +4873,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", - "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", "cpu": [ "x64" ], @@ -4854,9 +4890,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", - "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", "cpu": [ "x64" ], @@ -4871,9 +4907,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", - "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", "cpu": [ "x64" ], @@ -4885,9 +4921,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", - "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", "cpu": [ "arm64" ], @@ -4899,9 +4935,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", - "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", "cpu": [ "arm64" ], @@ -4913,9 +4949,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", - "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", "cpu": [ "ia32" ], @@ -4927,9 +4963,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", - "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", "cpu": [ "x64" ], @@ -4941,9 +4977,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", - "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", "cpu": [ "x64" ], @@ -4955,14 +4991,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.14.tgz", - "integrity": "sha512-rIEdtNTdCCTwuo7B4tMoq5qmbLXdBgmW6Ays1hyno//4OE+HFtvlWZd+hl6KceEyN00IcZ2HRaPnfd71E1JnoA==", + "version": "21.2.18", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.18.tgz", + "integrity": "sha512-XNEWvJSUg/ljLXgGVs7picBOtzVC4abBf2+i/ds9E7GaYYVyH19Mpgk6BOuMHAgRpjPWBAeWiBkTqetiR2Ps5Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.14", - "@angular-devkit/schematics": "21.2.14", + "@angular-devkit/core": "21.2.18", + "@angular-devkit/schematics": "21.2.18", "jsonc-parser": "3.3.1" }, "engines": { @@ -5080,9 +5116,9 @@ } }, "node_modules/@sigstore/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.0.tgz", - "integrity": "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.1.tgz", + "integrity": "sha512-qRsxPnCrbC/puegGxKuynfnxgLiHqWStrSjxkoB4YKqq3Z3s4cyZyj42ZdWFAEblNP65C+rBH8EuREHIXoi83g==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5132,14 +5168,14 @@ } }, "node_modules/@sigstore/verify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.0.tgz", - "integrity": "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.1.tgz", + "integrity": "sha512-qv7+G3J2cc6wwFj3yKvXOamzqhMwSk1ogPGmhpS8iXllcPrJaIIBA+4HbttlHVu1pqWTdmaCH/WE7UOC51kdoA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", + "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0" }, "engines": { @@ -5278,9 +5314,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -5654,14 +5690,14 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.4.tgz", - "integrity": "sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.4", + "@vitest/utils": "4.1.9", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -5675,8 +5711,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.4", - "vitest": "4.1.4" + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -5685,16 +5721,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", - "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -5703,13 +5739,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", - "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.4", + "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -5730,9 +5766,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", - "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", "dev": true, "license": "MIT", "dependencies": { @@ -5743,13 +5779,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", - "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.4", + "@vitest/utils": "4.1.9", "pathe": "^2.0.3" }, "funding": { @@ -5757,14 +5793,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", - "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -5773,9 +5809,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", - "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", "dev": true, "license": "MIT", "funding": { @@ -5783,13 +5819,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", - "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", + "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -6143,9 +6179,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", - "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6251,9 +6287,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", "dev": true, "funding": [ { @@ -6271,10 +6307,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", "update-browserslist-db": "^1.2.3" }, "bin": { @@ -6360,9 +6396,9 @@ } }, "node_modules/cacache/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -6419,9 +6455,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001788", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", - "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "version": "1.0.30001800", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", + "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", "dev": true, "funding": [ { @@ -6906,32 +6942,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cssstyle": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", - "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^5.0.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.28", - "css-tree": "^3.1.0", - "lru-cache": "^11.2.6" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/data-urls": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", @@ -7149,9 +7159,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.339", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.339.tgz", - "integrity": "sha512-Is+0BBHJ4NrdpAYiperrmp53pLywG/yV/6lIMTAnhxvzj/Cmn5Q/ogSHC6AKe7X+8kPLxxFk0cs5oc/3j/fxIg==", + "version": "1.5.383", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.383.tgz", + "integrity": "sha512-I2484/KkAvl8lm9VyjH2JnbOIV0d/UCqT7gbzs6l+o6Vmn9wgB66uVcKX+Vk6HrXtY6fbWTOEXuv8waDTuFNCw==", "dev": true, "license": "ISC" }, @@ -7206,13 +7216,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -7261,9 +7264,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7274,32 +7277,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escalade": { @@ -8237,9 +8240,9 @@ } }, "node_modules/hosted-git-info": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", "dev": true, "license": "ISC", "dependencies": { @@ -8250,9 +8253,9 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -8813,36 +8816,36 @@ } }, "node_modules/jsdom": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", - "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", "dev": true, "license": "MIT", "dependencies": { - "@acemir/cssom": "^0.9.31", - "@asamuzakjp/dom-selector": "^6.8.1", + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", "@bramus/specificity": "^2.4.2", - "@exodus/bytes": "^1.11.0", - "cssstyle": "^6.0.1", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", - "parse5": "^8.0.0", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.0", - "undici": "^7.21.0", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0", + "whatwg-url": "^16.0.1", "xml-name-validator": "^5.0.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" }, "peerDependencies": { "canvas": "^3.0.0" @@ -8853,6 +8856,16 @@ } } }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/jsdom/node_modules/whatwg-mimetype": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", @@ -9344,9 +9357,9 @@ } }, "node_modules/make-fetch-happen": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.5.tgz", - "integrity": "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==", + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.6.tgz", + "integrity": "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw==", "dev": true, "license": "ISC", "dependencies": { @@ -9783,9 +9796,9 @@ } }, "node_modules/ng-mocks": { - "version": "14.15.2", - "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.15.2.tgz", - "integrity": "sha512-3nI4qAzJMHnThkOKtPKcw88I7Q6psmOav41OSqOqELqa/6UTWCu1LfPtAYI0BMn1hjQ8VMXtMKXpgT1ajTnBRg==", + "version": "14.15.3", + "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.15.3.tgz", + "integrity": "sha512-J0UafeI2K5kc5oDhIinGu+VqT990b0sP2dlKV3JxXYTlaQxQ7Mm0LLrxGz10hsGGJVtn9JEKkhjnpb6oijLT3w==", "dev": true, "license": "MIT", "funding": { @@ -9889,21 +9902,21 @@ } }, "node_modules/node-gyp": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.2.0.tgz", - "integrity": "sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz", + "integrity": "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==", "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^15.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", + "undici": "^6.25.0", "which": "^6.0.0" }, "bin": { @@ -9939,6 +9952,16 @@ "node": ">=20" } }, + "node_modules/node-gyp/node_modules/undici": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/node-gyp/node_modules/which": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", @@ -9956,11 +9979,14 @@ } }, "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/nopt": { "version": "9.0.0", @@ -10245,9 +10271,9 @@ } }, "node_modules/p-map": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.5.tgz", + "integrity": "sha512-e8vJF4XdVkzqqSHguEMz41mQO1wKwxKm5ENrUJQUu9kLDCtn83cxbyHZcszr4QC5zEA7WffRRC4gsTecC7J9oA==", "dev": true, "license": "MIT", "engines": { @@ -10268,12 +10294,13 @@ } }, "node_modules/pacote": { - "version": "21.3.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz", - "integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==", + "version": "21.5.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.5.1.tgz", + "integrity": "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg==", "dev": true, "license": "ISC", "dependencies": { + "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", @@ -10287,7 +10314,6 @@ "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" @@ -10339,12 +10365,12 @@ "license": "MIT" }, "node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "entities": "^8.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -10392,12 +10418,12 @@ } }, "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -10460,9 +10486,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -10506,9 +10532,9 @@ } }, "node_modules/piscina": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.4.tgz", - "integrity": "sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.2.0.tgz", + "integrity": "sha512-DszUCKeVN/5G5QKo6jAVHL8fmKnkJvQ0ACiVgY7YGCq3TUB2oznAOayvZPIAdEThvhczkXR+qm3IHsNXpFCYfA==", "dev": true, "license": "MIT", "engines": { @@ -10683,20 +10709,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -11021,16 +11033,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -11138,13 +11140,13 @@ } }, "node_modules/rollup": { - "version": "4.60.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", - "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -11154,31 +11156,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.1", - "@rollup/rollup-android-arm64": "4.60.1", - "@rollup/rollup-darwin-arm64": "4.60.1", - "@rollup/rollup-darwin-x64": "4.60.1", - "@rollup/rollup-freebsd-arm64": "4.60.1", - "@rollup/rollup-freebsd-x64": "4.60.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", - "@rollup/rollup-linux-arm-musleabihf": "4.60.1", - "@rollup/rollup-linux-arm64-gnu": "4.60.1", - "@rollup/rollup-linux-arm64-musl": "4.60.1", - "@rollup/rollup-linux-loong64-gnu": "4.60.1", - "@rollup/rollup-linux-loong64-musl": "4.60.1", - "@rollup/rollup-linux-ppc64-gnu": "4.60.1", - "@rollup/rollup-linux-ppc64-musl": "4.60.1", - "@rollup/rollup-linux-riscv64-gnu": "4.60.1", - "@rollup/rollup-linux-riscv64-musl": "4.60.1", - "@rollup/rollup-linux-s390x-gnu": "4.60.1", - "@rollup/rollup-linux-x64-gnu": "4.60.1", - "@rollup/rollup-linux-x64-musl": "4.60.1", - "@rollup/rollup-openbsd-x64": "4.60.1", - "@rollup/rollup-openharmony-arm64": "4.60.1", - "@rollup/rollup-win32-arm64-msvc": "4.60.1", - "@rollup/rollup-win32-ia32-msvc": "4.60.1", - "@rollup/rollup-win32-x64-gnu": "4.60.1", - "@rollup/rollup-win32-x64-msvc": "4.60.1", + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", "fsevents": "~2.3.2" } }, @@ -11464,18 +11466,18 @@ } }, "node_modules/sigstore": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.0.tgz", - "integrity": "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.1.tgz", + "integrity": "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w==", "dev": true, "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", + "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0", - "@sigstore/sign": "^4.1.0", - "@sigstore/tuf": "^4.0.1", - "@sigstore/verify": "^3.1.0" + "@sigstore/sign": "^4.1.1", + "@sigstore/tuf": "^4.0.2", + "@sigstore/verify": "^3.1.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -11510,13 +11512,13 @@ } }, "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "^10.0.1", + "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -11997,9 +11999,9 @@ } }, "node_modules/tar": { - "version": "7.5.16", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", - "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", + "version": "7.5.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.19.tgz", + "integrity": "sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -12242,9 +12244,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", - "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", "dev": true, "license": "MIT", "engines": { @@ -12328,13 +12330,13 @@ } }, "node_modules/vite": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", - "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", + "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", @@ -12403,19 +12405,19 @@ } }, "node_modules/vitest": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", - "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.4", - "@vitest/mocker": "4.1.4", - "@vitest/pretty-format": "4.1.4", - "@vitest/runner": "4.1.4", - "@vitest/snapshot": "4.1.4", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -12443,12 +12445,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.4", - "@vitest/browser-preview": "4.1.4", - "@vitest/browser-webdriverio": "4.1.4", - "@vitest/coverage-istanbul": "4.1.4", - "@vitest/coverage-v8": "4.1.4", - "@vitest/ui": "4.1.4", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/package.json b/package.json index 2df5b30ef..06bcbcaa9 100644 --- a/package.json +++ b/package.json @@ -31,17 +31,17 @@ }, "private": true, "dependencies": { - "@angular/animations": "^21.2.16", - "@angular/cdk": "^21.2.6", - "@angular/common": "^21.2.16", - "@angular/compiler": "^21.2.16", - "@angular/core": "^21.2.16", - "@angular/forms": "^21.2.16", - "@angular/platform-browser": "^21.2.16", - "@angular/platform-browser-dynamic": "^21.2.16", - "@angular/platform-server": "^21.2.16", - "@angular/router": "^21.2.16", - "@angular/ssr": "^21.2.7", + "@angular/animations": "^21.2.17", + "@angular/cdk": "^21.2.14", + "@angular/common": "^21.2.17", + "@angular/compiler": "^21.2.17", + "@angular/core": "^21.2.17", + "@angular/forms": "^21.2.17", + "@angular/platform-browser": "^21.2.17", + "@angular/platform-browser-dynamic": "^21.2.17", + "@angular/platform-server": "^21.2.17", + "@angular/router": "^21.2.17", + "@angular/ssr": "^21.2.18", "@centerforopenscience/markdown-it-atrules": "^0.1.2", "@citation-js/core": "^0.7.21", "@citation-js/plugin-csl": "^0.7.21", @@ -78,9 +78,9 @@ "@angular-eslint/eslint-plugin": "^21.3.0", "@angular-eslint/eslint-plugin-template": "^21.3.0", "@angular-eslint/template-parser": "^21.3.0", - "@angular/build": "^21.2.14", - "@angular/cli": "^21.2.14", - "@angular/compiler-cli": "^21.2.16", + "@angular/build": "^21.2.18", + "@angular/cli": "^21.2.18", + "@angular/compiler-cli": "^21.2.17", "@commitlint/cli": "^20.4.3", "@commitlint/config-conventional": "^20.4.3", "@eslint/js": "^10.0.1", @@ -89,7 +89,7 @@ "@types/gapi.auth2": "^0.0.61", "@types/markdown-it": "^14.1.2", "@types/node": "^20.17.19", - "@vitest/coverage-v8": "^4.1.1", + "@vitest/coverage-v8": "^4.1.9", "angular-eslint": "^21.3.0", "angularx-qrcode": "^21.0.4", "eslint": "^10.0.2", @@ -98,14 +98,14 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unused-imports": "^4.4.1", "husky": "^9.1.7", - "jsdom": "^28.0.0", + "jsdom": "^29.1.1", "lint-staged": "^16.3.2", - "ng-mocks": "^14.15.1", + "ng-mocks": "^14.15.3", "prettier": "3.8.1", "source-map-explorer": "^2.5.3", "typescript": "~5.9.3", "typescript-eslint": "^8.56.1", - "vitest": "^4.1.1" + "vitest": "^4.1.9" }, "lint-staged": { "**/*.{ts,html,scss}": [ From 36a9bcc66a55e8a9a37ebf56b79a0505b72a0024 Mon Sep 17 00:00:00 2001 From: nsemets Date: Thu, 23 Jul 2026 12:13:59 +0300 Subject: [PATCH 04/11] fix(vulnerabilities): fixed more issues --- package-lock.json | 247 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 190 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b357d9d7..0db2ea746 100644 --- a/package-lock.json +++ b/package-lock.json @@ -356,13 +356,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.18.tgz", - "integrity": "sha512-PakHs+Eefx06KORDFyH4wmkIZ/wm4mI4DqhXe4XFuWJOazMQoYJxPmMeby47BD0HhvJN7BskN61CPS8HCAvICg==", + "version": "21.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.19.tgz", + "integrity": "sha512-AG3Fzh9wJCmKBfxUQOUWaEHMj5Gq2O+Msf1z52aDSxbVhs5/iSQcXGPv/DLdAXu7d4xmQhLouNe9Glaq2omDyw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.18", + "@angular-devkit/core": "21.2.19", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", "ora": "9.3.0", @@ -374,6 +374,34 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { + "version": "21.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.19.tgz", + "integrity": "sha512-dtpJMQBz5nhkcIogPmXP/aT2Ak8m/wLRPOSTI/g4vSJSuGiI53PgtWq4/wfQga6E6wdM2XWsblAE89d8w5heQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, "node_modules/@angular-eslint/builder": { "version": "21.3.1", "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.3.1.tgz", @@ -616,19 +644,19 @@ } }, "node_modules/@angular/cli": { - "version": "21.2.18", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.18.tgz", - "integrity": "sha512-WOZF4p0SnrmBpNeiOA2pdp9OBvGnOSLWbGdRLXJykyseIiEn7+N+GZp+ZA1aNZB4SWolpYCZfTYwkpo6Sf/LXg==", + "version": "21.2.19", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.19.tgz", + "integrity": "sha512-i78NzvoNonAY17QgzSmqrYnXHmEfraLv4wZ/o/m3efxuz61ZJ+5X/PsCeAhbwBvQfRrPRQaJV2tK9vGjHa+U6w==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.18", - "@angular-devkit/core": "21.2.18", - "@angular-devkit/schematics": "21.2.18", + "@angular-devkit/architect": "0.2102.19", + "@angular-devkit/core": "21.2.19", + "@angular-devkit/schematics": "21.2.19", "@inquirer/prompts": "7.10.1", "@listr2/prompt-adapter-inquirer": "3.0.5", "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.18", + "@schematics/angular": "21.2.19", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.48.1", "ini": "6.0.0", @@ -650,6 +678,53 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { + "version": "0.2102.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.19.tgz", + "integrity": "sha512-cj4tzUMiloLTg5rNf17E8MsvIxCWYoBiBsaj7ns6dgXqT9XCeG+J0TA2t1M+N9uuqfeLd22U/rYoCkADmcircQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.2.19", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/@angular-devkit/core": { + "version": "21.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.19.tgz", + "integrity": "sha512-dtpJMQBz5nhkcIogPmXP/aT2Ak8m/wLRPOSTI/g4vSJSuGiI53PgtWq4/wfQga6E6wdM2XWsblAE89d8w5heQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, "node_modules/@angular/common": { "version": "21.2.17", "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.17.tgz", @@ -4991,14 +5066,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.2.18", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.18.tgz", - "integrity": "sha512-XNEWvJSUg/ljLXgGVs7picBOtzVC4abBf2+i/ds9E7GaYYVyH19Mpgk6BOuMHAgRpjPWBAeWiBkTqetiR2Ps5Q==", + "version": "21.2.19", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.19.tgz", + "integrity": "sha512-eL+UU9eizoadhDB4YEctRmmo0A5iwrSmGzeuEa6akrq8nLGVWM8zO91HTJutkPqGQjelF+UOiOShsQSZAU9SIQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.18", - "@angular-devkit/schematics": "21.2.18", + "@angular-devkit/core": "21.2.19", + "@angular-devkit/schematics": "21.2.19", "jsonc-parser": "3.3.1" }, "engines": { @@ -5007,6 +5082,34 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { + "version": "21.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.19.tgz", + "integrity": "sha512-dtpJMQBz5nhkcIogPmXP/aT2Ak8m/wLRPOSTI/g4vSJSuGiI53PgtWq4/wfQga6E6wdM2XWsblAE89d8w5heQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, "node_modules/@sentry-internal/browser-utils": { "version": "10.49.0", "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.49.0.tgz", @@ -6223,20 +6326,20 @@ } }, "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.0.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" }, "engines": { "node": ">=18" @@ -6246,6 +6349,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -6274,9 +6390,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", "dev": true, "license": "MIT", "dependencies": { @@ -7797,9 +7913,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", "dev": true, "funding": [ { @@ -7877,9 +7993,9 @@ "license": "MIT" }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", "dev": true, "license": "MIT", "dependencies": { @@ -8230,9 +8346,9 @@ } }, "node_modules/hono": { - "version": "4.12.25", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", - "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", + "version": "4.12.31", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.31.tgz", + "integrity": "sha512-zJIHFrl6bq3RDd2YusFNCDlM8qUprxKswyi/OPzPyzKDdyBXDqWx8bZlZ7R+saTdSTatUmb3O7K4SspGPaEOQg==", "dev": true, "license": "MIT", "engines": { @@ -8446,9 +8562,9 @@ } }, "node_modules/immutable": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", - "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", "dev": true, "license": "MIT" }, @@ -8793,9 +8909,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", "dev": true, "funding": [ { @@ -9014,9 +9130,9 @@ "license": "MIT" }, "node_modules/linkify-it": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", - "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", "funding": [ { "type": "github", @@ -11062,9 +11178,9 @@ "license": "MIT" }, "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -11613,9 +11729,9 @@ "license": "MIT" }, "node_modules/source-map-explorer/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -12186,17 +12302,34 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typescript": { From cbc078ed9976fcef8e7d0b9f68d44adc799b0ccc Mon Sep 17 00:00:00 2001 From: futa-ikeda <51409893+futa-ikeda@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:09:56 -0400 Subject: [PATCH 05/11] chore(license/copyright): Update license and copyright year (#1034) ## Purpose - Happy (belated) New Year! ## Summary of Changes - Update License and Copyright info --- LICENSE | 2 +- src/assets/i18n/en.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 6b3cb391f..851013921 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2025 Center for Open Science +Copyright 2026 Center for Open Science Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index f3a201da3..87eb3ea27 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -710,7 +710,7 @@ "storageLocation": "OSF Storage" }, "footer": { - "copyright": "Copyright © 2011-2025", + "copyright": "Copyright © 2011-2026", "links": { "api": "API", "centerForOpenScience": "Center for Open Science", From 31fe4f7c5a55a1889233da400f91dab3f7251651 Mon Sep 17 00:00:00 2001 From: nsemets Date: Fri, 24 Jul 2026 19:46:11 +0300 Subject: [PATCH 06/11] [ENG-11256] Improve models structure (#998) - Ticket: https://openscience.atlassian.net/browse/ENG-11256 - Feature flag: n/a ## Summary of Changes 1. Updated JSON:API models. 2. Created reusable models. 3. Split models for better readability. 4. Update unit tests. --- docs/arch.md | 120 ++++--- docs/models.md | 94 ++++++ docs/ngxs.md | 54 +-- src/app/core/constants/nav-items.constant.ts | 2 +- .../filters-section.component.ts | 2 +- .../mappers/institution-departments.mapper.ts | 8 +- .../institution-summary-index.mapper.ts | 10 +- .../mappers/institution-users.mapper.ts | 2 +- .../models/institution-department.model.ts | 1 - .../institution-departments-json-api.model.ts | 25 +- ...ution-index-value-search-json-api.model.ts | 63 ++-- ...titution-summary-metrics-json-api.model.ts | 43 +-- .../institution-users-json-api.model.ts | 43 +-- .../models/send-message-json-api.model.ts | 23 +- .../store/institutions-admin.model.ts | 4 +- .../store/institutions-admin.selectors.ts | 32 +- .../store/institutions-admin.state.ts | 22 +- .../mappers/related-counts.mapper.ts | 10 +- .../models/node-analytics-json-api.model.ts | 19 +- .../models/related-counts-json-api.model.ts | 46 +-- .../services/resource-analytics.service.ts | 4 +- ...tion-confirmation-dialog.component.spec.ts | 16 +- ...ollection-confirmation-dialog.component.ts | 19 +- .../add-to-collection.component.ts | 6 +- .../collection-metadata-step.component.html | 4 +- ...collection-metadata-step.component.spec.ts | 38 +-- .../collection-metadata-step.component.ts | 16 +- .../collections-discover.component.spec.ts | 55 ++-- .../collections-discover.component.ts | 6 +- .../collection-license-json-api.model.ts | 40 +-- .../models/project-metadata-form.model.ts | 3 +- .../add-to-collection.model.ts | 2 +- .../mappers/file-custom-metadata.mapper.ts | 5 +- .../files/mappers/file-revision.mapper.ts | 9 +- .../files/mappers/resource-metadata.mapper.ts | 8 +- .../models/file-metadata-response.model.ts | 16 + .../models/file-revisions-response.model.ts | 23 ++ .../get-custom-metadata-response.model.ts | 26 -- .../get-file-metadata-response.model.ts | 10 - .../get-file-revisions-response.model.ts | 16 - ...resource-custom-metadata-response.model.ts | 29 -- .../get-resource-short-info-response.model.ts | 17 - .../models/get-short-info-response.model.ts | 17 - .../models/node-short-info-response.model.ts | 20 ++ ...resource-custom-metadata-response.model.ts | 30 ++ .../file-detail/file-detail.component.spec.ts | 69 ++-- .../file-detail/file-detail.component.ts | 12 +- src/app/features/files/store/files.state.ts | 12 +- .../pages/dashboard/dashboard.component.ts | 2 +- .../meetings/mappers/meetings.mapper.ts | 12 +- .../models/meetings-json-api.model.ts | 54 +-- .../meetings/services/meetings.service.ts | 12 +- .../cedar-template-form.component.html | 6 +- .../cedar-template-form.component.spec.ts | 9 +- .../cedar-template-form.component.ts | 18 +- .../metadata-collection-item.component.html | 2 +- ...metadata-collection-item.component.spec.ts | 2 +- .../metadata-collection-item.component.ts | 15 +- .../metadata-collections.component.ts | 10 +- .../metadata/mappers/cedar-metadata.mapper.ts | 42 +++ .../metadata/mappers/cedar-records.mapper.ts | 4 +- src/app/features/metadata/mappers/index.ts | 1 + .../metadata/mappers/metadata.mapper.ts | 12 +- .../features/metadata/metadata.component.ts | 14 +- .../models/cedar-metadata-attributes.model.ts | 4 + .../cedar-metadata-record-json-api.model.ts | 27 ++ .../models/cedar-metadata-record.model.ts | 16 + .../cedar-metadata-template-json-api.model.ts | 19 ++ .../models/cedar-metadata-template.model.ts | 259 +-------------- .../metadata/models/cedar-template.model.ts | 78 +++++ src/app/features/metadata/models/index.ts | 5 + .../models/metadata-json-api.model.ts | 71 ++-- src/app/features/metadata/models/ror.model.ts | 102 +++--- .../add-metadata/add-metadata.component.html | 6 +- .../add-metadata.component.spec.ts | 9 +- .../add-metadata/add-metadata.component.ts | 14 +- .../metadata/store/metadata.actions.ts | 4 +- .../features/metadata/store/metadata.model.ts | 16 +- .../metadata/store/metadata.selectors.ts | 2 +- .../features/metadata/store/metadata.state.ts | 16 +- ...llection-submission-item.component.spec.ts | 3 +- .../collection-submission-item.component.ts | 2 +- .../collection-submissions-list.component.ts | 2 +- .../moderation/mappers/moderation.mapper.ts | 21 -- .../mappers/preprint-moderation.mapper.ts | 15 +- .../mappers/registry-moderation.mapper.ts | 7 +- ...submission-review-action-json-api.model.ts | 51 +-- .../models/moderator-json-api.model.ts | 41 +-- .../preprint-related-count-json-api.model.ts | 40 ++- .../preprint-review-action-json-api.model.ts | 59 ++-- .../preprint-submission-json-api.model.ts | 29 +- ...nt-withdrawal-submission-json-api.model.ts | 36 +- .../models/registry-json-api.model.ts | 16 +- .../models/review-action-json-api.model.ts | 9 +- .../moderation/services/moderators.service.ts | 14 +- .../services/preprint-moderation.service.ts | 12 +- .../services/provider-subscription.service.ts | 12 +- .../collections-moderation.model.ts | 2 +- .../my-projects/my-projects.component.ts | 2 +- .../project-download-options.service.spec.ts | 8 +- .../project-download-options.service.ts | 2 +- .../mappers/preprint-providers.mapper.ts | 6 +- .../preprints/mappers/preprints.mapper.ts | 46 +-- src/app/features/preprints/models/index.ts | 1 - .../preprint-licenses-json-api.model.ts | 29 +- .../preprint-provider-json-api.model.ts | 75 +++-- .../preprint-request-action-json-api.model.ts | 25 +- .../models/preprint-request-json-api.model.ts | 22 +- .../services/preprint-files.service.ts | 38 +-- .../services/preprint-licenses.service.ts | 14 +- .../services/preprint-providers.service.ts | 12 +- .../services/preprints-projects.service.ts | 36 +- .../preprints/services/preprints.service.ts | 107 ++---- .../profile-information.component.spec.ts | 4 +- .../profile-information.component.ts | 2 +- .../link-resource-dialog.component.spec.ts | 2 +- .../link-resource-dialog.component.ts | 2 +- .../overview-collections.component.html | 4 +- .../overview-collections.component.spec.ts | 19 +- .../overview-collections.component.ts | 16 +- .../mappers/project-overview.mapper.ts | 13 +- .../overview/models/project-overview.model.ts | 11 - .../services/project-overview.service.ts | 15 +- .../overview/store/project-overview.state.ts | 4 +- .../connect-configured-addon.component.ts | 4 +- .../project-addons.component.html | 2 +- .../project-addons.component.ts | 4 +- .../services/registrations.service.ts | 11 +- .../settings/mappers/settings.mapper.ts | 4 +- .../models/project-settings-response.model.ts | 34 +- .../settings/models/project-settings.model.ts | 14 +- .../settings/services/settings.service.ts | 12 +- .../project/wiki/wiki.component.spec.ts | 3 +- .../features/project/wiki/wiki.component.ts | 2 +- .../registries/services/registries.service.ts | 53 ++- .../store/handlers/files.handlers.ts | 4 +- .../resource-type-options.constant.ts | 2 +- .../registry/mappers/linked-nodes.mapper.ts | 9 +- src/app/features/registry/models/index.ts | 2 - .../models/linked-nodes-json-api.model.ts | 31 -- .../registry/models/linked-nodes.model.ts | 2 - .../linked-registrations-json-api.model.ts | 29 +- .../registry/models/linked-response.model.ts | 27 -- .../registration-overview-json-api.model.ts | 48 +-- .../registry-components-json-api.model.ts | 27 +- .../models/registry-overview.model.ts | 11 +- .../add-resource-response-json-api.model.ts | 16 - .../get-registry-resources-json-api.model.ts | 4 - .../registry/models/resources/index.ts | 3 +- .../resource-response-json-api.model.ts | 15 + .../registry-resources.component.spec.ts | 4 +- .../registry-wiki.component.spec.ts | 2 +- .../registry-wiki/registry-wiki.component.ts | 2 +- .../services/registry-components.service.ts | 13 +- .../services/registry-links.service.ts | 32 +- .../services/registry-overview.service.ts | 15 +- .../registry-components.state.ts | 2 +- .../registry-links/registry-links.model.ts | 14 +- .../registry-links/registry-links.state.ts | 4 +- .../registry/store/registry/registry.state.ts | 4 +- .../mappers/external-identities.mapper.ts | 8 +- ...ngs.model.ts => account-settings.model.ts} | 0 .../settings/account-settings/models/index.ts | 2 +- ...ccount-settings-response-json-api.model.ts | 13 +- .../list-identities-response.model.ts | 12 +- .../mappers/developer-app.mapper.ts | 4 +- .../models/developer-app-json-api.model.ts | 58 ++-- .../services/developer-apps.service.ts | 19 +- .../notification-subscription.service.ts | 10 +- .../connect-addon/connect-addon.component.ts | 4 +- .../settings/tokens/mappers/scope.mapper.ts | 4 +- .../settings/tokens/mappers/token.mapper.ts | 4 +- .../tokens/models/scope-json-api.model.ts | 15 +- .../tokens/models/token-json-api.model.ts | 40 +-- .../tokens/services/tokens.service.spec.ts | 47 ++- .../tokens/services/tokens.service.ts | 20 +- .../addon-setup-account-form.component.ts | 2 +- .../filter-chips/filter-chips.component.ts | 2 +- .../global-search/global-search.component.ts | 2 +- .../google-file-picker.component.spec.ts | 2 +- .../google-file-picker.component.ts | 4 +- .../metadata-tabs.component.spec.ts | 9 +- .../metadata-tabs/metadata-tabs.component.ts | 8 +- .../my-projects-table.component.spec.ts | 2 +- .../my-projects-table.component.ts | 2 +- .../recent-activity-list.component.ts | 4 +- .../wiki-list/wiki-list.component.spec.ts | 2 +- .../wiki/wiki-list/wiki-list.component.ts | 2 +- src/app/shared/enums/wiki-modes.enum.ts | 5 + .../wiki-type.enum.ts} | 0 .../shared/mappers/activity-logs.mapper.ts | 141 +++----- src/app/shared/mappers/addon.mapper.ts | 37 ++- src/app/shared/mappers/banner.mapper.ts | 2 +- src/app/shared/mappers/citations.mapper.ts | 8 +- .../mappers/collections/collections.mapper.ts | 42 +-- .../contributors/contributors.mapper.ts | 26 +- .../institutions/institutions.mapper.ts | 8 +- src/app/shared/mappers/my-resources.mapper.ts | 3 +- .../shared/mappers/nodes/base-node.mapper.ts | 15 +- .../shared/mappers/regions/regions-mapper.ts | 2 +- .../registration/registration.mapper.ts | 2 +- src/app/shared/mappers/user/user.mapper.ts | 2 +- .../shared/mappers/view-only-links.mapper.ts | 7 +- src/app/shared/mappers/wiki/wiki.mapper.ts | 32 +- .../activity-log-with-display.model.ts | 4 +- .../activity-logs-json-api.model.ts | 285 +++++++--------- .../activity-logs/activity-logs.model.ts | 184 +++++------ .../addons/addon-included-json-api.model.ts | 5 + .../models/addons/addon-json-api.model.ts | 311 ------------------ .../addons/addon-operations-json-api.model.ts | 98 +++--- .../addons/addon-reference-json-api.model.ts | 23 ++ .../addons/authorized-addon-json-api.model.ts | 49 +++ .../addons/configured-addon-json-api.model.ts | 77 +++++ .../addons/external-addon-json-api.model.ts | 21 ++ .../addons/operation-invocation.model.ts | 10 +- .../models/addons/resource-reference.model.ts | 4 + .../models/addons/user-reference.model.ts | 4 + .../shared/models/banner-json-api.model.ts | 24 ++ .../shared/models/banner.json-api.model.ts | 18 - .../models/brand/brand-json-api.model.ts | 13 + .../models/brand/brand.json-api.model.ts | 13 - .../citation-style-json-api.model.ts | 22 +- .../custom-citation-payload-json-api.model.ts | 15 +- .../styled-citation-json-api.model.ts | 15 +- .../collection-details-json-api.model.ts | 39 +++ .../collections/collection-details.model.ts | 11 + .../collection-provider-json-api.model.ts | 29 ++ .../collections/collection-provider.model.ts | 25 ++ ...ction-submission-payload-json-api.model.ts | 41 ++- .../collection-submissions-json-api.model.ts | 82 +++++ ...del.ts => collection-submissions.model.ts} | 43 +-- .../collections/collections-json-api.model.ts | 111 ------- .../shared/models/common/json-api.model.ts | 49 --- .../models/common/json-api/embeds.model.ts | 9 + .../models/common/json-api/links.model.ts | 13 + .../models/common/json-api/meta.model.ts | 11 + .../common/json-api/relationships.model.ts | 42 +++ .../models/common/json-api/resource.model.ts | 10 + .../models/common/json-api/responses.model.ts | 22 ++ .../contributor-add-request.model.ts | 25 ++ .../contributor-response-json-api.model.ts | 79 +---- .../emails/account-emails-json-api.model.ts | 19 +- .../files/file-folder-json-api.model.ts | 46 +-- .../models/files/file-json-api.model.ts | 76 ++--- .../files/file-payload-json-api.model.ts | 18 +- .../files/file-version-json-api.model.ts | 20 +- src/app/shared/models/files/file.model.ts | 5 +- ...ata.model.ts => google-file-data.model.ts} | 0 ...r.model.ts => google-file-picker.model.ts} | 2 +- .../files/resource-files-links.model.ts | 4 - .../models/google-drive-folder.model.ts | 4 - .../models/guid-response-json-api.model.ts | 42 +-- .../identifiers/identifier-json-api.model.ts | 10 +- .../institution-json-api.model.ts | 59 +--- src/app/shared/models/language-code.model.ts | 4 - .../models/license/licenses-json-api.model.ts | 20 +- .../my-resources/my-resources-item.model.ts | 11 + .../my-resources-json-api.model.ts | 22 ++ .../models/my-resources/my-resources.model.ts | 33 -- .../node-links/node-link-json-api.model.ts | 19 +- .../models/node-links/node-link.model.ts | 8 - .../base-node-attributes-json-api.model.ts | 9 +- .../nodes/base-node-data-json-api.model.ts | 5 +- .../nodes/base-node-embeds-json-api.model.ts | 83 +---- .../nodes/base-node-links-json-api.model.ts | 5 - .../base-node-relationships-json-api.model.ts | 80 ++--- .../nodes/node-preprint-json-api.model.ts | 20 +- .../nodes/node-storage-json-api.model.ts | 19 +- .../models/nodes/nodes-json-api.model.ts | 59 ++-- ...otification-subscription-json-api.model.ts | 45 ++- .../shared/models/pagination-links.model.ts | 2 +- .../preprints}/preprint-json-api.model.ts | 105 +++--- .../preprints-provider-json-api.model.ts | 2 +- .../provider/providers-json-api.model.ts | 11 +- .../registration-provider-json-api.model.ts | 34 +- .../models/regions/regions-json-api.model.ts | 10 + .../models/regions/regions.json-api.model.ts | 18 - .../registration-json-api.model.ts | 258 +++++---------- .../registration-node-json-api.model.ts | 14 +- .../registration/registration-node.model.ts | 9 - .../models/registration/registration.model.ts | 8 +- .../schema-blocks-json-api.model.ts | 11 +- .../schema-response-json-api.model.ts | 46 +++ .../request-access-json-api.model.ts | 20 +- .../shared/models/resource-metadata.model.ts | 18 +- .../review-action-payload-json-api.model.ts | 29 +- ...oved.ts => filter-option-removed.model.ts} | 0 .../search/filter-options-json-api.model.ts | 19 +- ...dex-card-search-included-json-api.model.ts | 64 ++++ .../index-card-search-json-api.model.ts | 209 ++---------- ...dex-card-search-metadata-json-api.model.ts | 98 ++++++ .../shared/models/search/resource.model.ts | 1 - .../models/subject/subjects-json-api.model.ts | 57 +--- .../user-related-counts-json-api.model.ts | 58 +--- src/app/shared/models/user/creator.model.ts | 4 + .../shared/models/user/user-json-api.model.ts | 27 +- src/app/shared/models/user/user.model.ts | 2 +- .../view-only-link-response.model.ts | 37 ++- .../view-only-links/view-only-link.model.ts | 7 +- .../shared/models/wiki/wiki-json-api.model.ts | 36 ++ src/app/shared/models/wiki/wiki-menu.model.ts | 2 +- src/app/shared/models/wiki/wiki.model.ts | 84 ----- .../activity-log-display.service.ts | 6 +- .../activity-log-formatter.service.spec.ts | 32 +- .../activity-log-formatter.service.ts | 50 +-- .../activity-log-url-builder.service.ts | 26 +- .../activity-logs/activity-logs.service.ts | 20 +- .../services/addons/addon-form.service.ts | 6 +- .../shared/services/addons/addons.service.ts | 102 +++--- src/app/shared/services/banners.service.ts | 5 +- src/app/shared/services/bookmarks.service.ts | 13 +- src/app/shared/services/citations.service.ts | 15 +- .../shared/services/collections.service.ts | 60 ++-- .../shared/services/contributors.service.ts | 5 +- .../datacite/datacite.service.spec.ts | 3 - src/app/shared/services/files.service.spec.ts | 4 +- src/app/shared/services/files.service.ts | 89 ++--- .../shared/services/global-search.service.ts | 1 - .../shared/services/institutions.service.ts | 3 +- src/app/shared/services/json-api.service.ts | 2 +- src/app/shared/services/metadata.service.ts | 58 ++-- .../services/my-resources.service.spec.ts | 4 +- .../shared/services/my-resources.service.ts | 26 +- src/app/shared/services/node-links.service.ts | 12 +- src/app/shared/services/regions.service.ts | 2 +- .../services/registration-provider.service.ts | 7 +- src/app/shared/services/resource.service.ts | 19 +- src/app/shared/services/wiki.service.ts | 91 ++--- .../activity-logs/activity-logs.model.ts | 4 +- .../activity-logs/activity-logs.selectors.ts | 4 +- .../shared/stores/addons/addons.actions.ts | 6 +- src/app/shared/stores/addons/addons.model.ts | 13 +- .../shared/stores/addons/addons.selectors.ts | 13 +- .../stores/bookmarks/bookmarks.model.ts | 2 +- .../stores/collections/collections.model.ts | 4 +- .../global-search/global-search.state.spec.ts | 166 ++++------ .../institutions-search.model.ts | 4 +- .../institutions-search.selectors.ts | 6 +- .../institutions-search.state.ts | 6 +- .../stores/my-resources/my-resources.model.ts | 2 +- .../my-resources/my-resources.selectors.ts | 2 +- .../stores/my-resources/my-resources.state.ts | 6 +- .../stores/node-links/node-links.actions.ts | 2 +- .../shared/stores/subjects/subjects.model.ts | 4 +- .../stores/subjects/subjects.selectors.ts | 14 +- .../shared/stores/subjects/subjects.state.ts | 12 +- src/app/shared/stores/wiki/wiki.actions.ts | 2 +- src/app/shared/stores/wiki/wiki.state.ts | 4 +- .../data/addons/addons.configured.data.ts | 37 +-- .../data/collections/cedar-metadata.mock.ts | 28 +- .../collection-submissions.mock.ts | 2 +- src/testing/data/dashboard/dasboard.data.ts | 72 ---- .../data/global-search/global-search.data.ts | 29 ++ src/testing/mocks/activity-log.mock.ts | 18 +- src/testing/mocks/admin-institutions.mock.ts | 4 +- ...ar-metadata-data-template-json-api.mock.ts | 5 +- .../mocks/cedar-metadata-domain.mock.ts | 13 + .../mocks/cedar-metadata-record.mock.ts | 15 +- .../mocks/collections-submissions.mock.ts | 5 +- src/testing/mocks/data.mock.ts | 2 +- src/testing/mocks/linked-node.mock.ts | 2 - src/testing/mocks/my-resources.mock.ts | 2 +- src/testing/mocks/project-overview.mock.ts | 3 - src/testing/mocks/submission.mock.ts | 2 +- .../activity-log-display.service.mock.ts | 4 +- src/testing/providers/files-service.mock.ts | 27 +- 366 files changed, 4055 insertions(+), 5033 deletions(-) create mode 100644 docs/models.md create mode 100644 src/app/features/files/models/file-metadata-response.model.ts create mode 100644 src/app/features/files/models/file-revisions-response.model.ts delete mode 100644 src/app/features/files/models/get-custom-metadata-response.model.ts delete mode 100644 src/app/features/files/models/get-file-metadata-response.model.ts delete mode 100644 src/app/features/files/models/get-file-revisions-response.model.ts delete mode 100644 src/app/features/files/models/get-resource-custom-metadata-response.model.ts delete mode 100644 src/app/features/files/models/get-resource-short-info-response.model.ts delete mode 100644 src/app/features/files/models/get-short-info-response.model.ts create mode 100644 src/app/features/files/models/node-short-info-response.model.ts create mode 100644 src/app/features/files/models/resource-custom-metadata-response.model.ts create mode 100644 src/app/features/metadata/mappers/cedar-metadata.mapper.ts create mode 100644 src/app/features/metadata/models/cedar-metadata-attributes.model.ts create mode 100644 src/app/features/metadata/models/cedar-metadata-record-json-api.model.ts create mode 100644 src/app/features/metadata/models/cedar-metadata-record.model.ts create mode 100644 src/app/features/metadata/models/cedar-metadata-template-json-api.model.ts create mode 100644 src/app/features/metadata/models/cedar-template.model.ts delete mode 100644 src/app/features/registry/models/linked-nodes-json-api.model.ts delete mode 100644 src/app/features/registry/models/linked-response.model.ts delete mode 100644 src/app/features/registry/models/resources/add-resource-response-json-api.model.ts delete mode 100644 src/app/features/registry/models/resources/get-registry-resources-json-api.model.ts create mode 100644 src/app/features/registry/models/resources/resource-response-json-api.model.ts rename src/app/features/settings/account-settings/models/{account.settings.model.ts => account-settings.model.ts} (100%) create mode 100644 src/app/shared/enums/wiki-modes.enum.ts rename src/app/shared/{models/wiki/wiki-type.model.ts => enums/wiki-type.enum.ts} (100%) create mode 100644 src/app/shared/models/addons/addon-included-json-api.model.ts delete mode 100644 src/app/shared/models/addons/addon-json-api.model.ts create mode 100644 src/app/shared/models/addons/addon-reference-json-api.model.ts create mode 100644 src/app/shared/models/addons/authorized-addon-json-api.model.ts create mode 100644 src/app/shared/models/addons/configured-addon-json-api.model.ts create mode 100644 src/app/shared/models/addons/external-addon-json-api.model.ts create mode 100644 src/app/shared/models/addons/resource-reference.model.ts create mode 100644 src/app/shared/models/addons/user-reference.model.ts create mode 100644 src/app/shared/models/banner-json-api.model.ts delete mode 100644 src/app/shared/models/banner.json-api.model.ts create mode 100644 src/app/shared/models/brand/brand-json-api.model.ts delete mode 100644 src/app/shared/models/brand/brand.json-api.model.ts create mode 100644 src/app/shared/models/collections/collection-details-json-api.model.ts create mode 100644 src/app/shared/models/collections/collection-details.model.ts create mode 100644 src/app/shared/models/collections/collection-provider-json-api.model.ts create mode 100644 src/app/shared/models/collections/collection-provider.model.ts create mode 100644 src/app/shared/models/collections/collection-submissions-json-api.model.ts rename src/app/shared/models/collections/{collections.model.ts => collection-submissions.model.ts} (59%) delete mode 100644 src/app/shared/models/collections/collections-json-api.model.ts delete mode 100644 src/app/shared/models/common/json-api.model.ts create mode 100644 src/app/shared/models/common/json-api/embeds.model.ts create mode 100644 src/app/shared/models/common/json-api/links.model.ts create mode 100644 src/app/shared/models/common/json-api/meta.model.ts create mode 100644 src/app/shared/models/common/json-api/relationships.model.ts create mode 100644 src/app/shared/models/common/json-api/resource.model.ts create mode 100644 src/app/shared/models/common/json-api/responses.model.ts create mode 100644 src/app/shared/models/contributors/contributor-add-request.model.ts rename src/app/shared/models/files/{google-file.data.model.ts => google-file-data.model.ts} (100%) rename src/app/shared/models/files/{google-file.picker.model.ts => google-file-picker.model.ts} (86%) delete mode 100644 src/app/shared/models/files/resource-files-links.model.ts delete mode 100644 src/app/shared/models/google-drive-folder.model.ts delete mode 100644 src/app/shared/models/language-code.model.ts create mode 100644 src/app/shared/models/my-resources/my-resources-item.model.ts create mode 100644 src/app/shared/models/my-resources/my-resources-json-api.model.ts delete mode 100644 src/app/shared/models/my-resources/my-resources.model.ts delete mode 100644 src/app/shared/models/node-links/node-link.model.ts delete mode 100644 src/app/shared/models/nodes/base-node-links-json-api.model.ts rename src/app/{features/preprints/models => shared/models/preprints}/preprint-json-api.model.ts (53%) create mode 100644 src/app/shared/models/regions/regions-json-api.model.ts delete mode 100644 src/app/shared/models/regions/regions.json-api.model.ts create mode 100644 src/app/shared/models/registration/schema-response-json-api.model.ts rename src/app/shared/models/search/{filter-option-removed.ts => filter-option-removed.model.ts} (100%) create mode 100644 src/app/shared/models/search/index-card-search-included-json-api.model.ts create mode 100644 src/app/shared/models/search/index-card-search-metadata-json-api.model.ts create mode 100644 src/app/shared/models/user/creator.model.ts create mode 100644 src/app/shared/models/wiki/wiki-json-api.model.ts delete mode 100644 src/testing/data/dashboard/dasboard.data.ts create mode 100644 src/testing/data/global-search/global-search.data.ts create mode 100644 src/testing/mocks/cedar-metadata-domain.mock.ts diff --git a/docs/arch.md b/docs/arch.md index c926abcef..e6f34845c 100644 --- a/docs/arch.md +++ b/docs/arch.md @@ -1,59 +1,97 @@ # 📂 Folder Structure -Project based on principle **Feature-based Architecture**, this approach provides reusable and consistant -features across the application. +Project based on principle **Feature-based Architecture**: each feature owns its UI, routes, models, mappers, services, and store when needed. Shared and core code live outside features. ```bash 📦 src/ - ├── 📂 features/ # Каталог із функціональними модулями - │ ├── 📂 feature-name/ - │ │ ├── 📂 feature.component.ts/html/scss # Component with template and styles, and base logic file - │ │ ├── 📂 feature-service.ts # Service or Facade to provide data for NGXS - │ │ ├── 📂 feature.store.ts # NGXS Store for feature - │ │ ├── 📂 feature.entitity.ts # Feature Interface for data, Types, Enums - │ │ ├── 📂 feature.guards.ts # Guard's for feature routing and permissions - │ │ ├── 📂 feature.resolvers.ts # Resolvers for data fetching and preloading - │ │ ├── 📂 feature.utils.ts # Additinal utils for feature (formBuilders, converters, mappers) - │ │ ├── feature.module.ts # Optional, if standalone - │ │ ├── feature.routing.ts # Export of standalone components by path + ├── 📂 app/ + │ ├── 📂 features/ # Feature modules + │ │ └── 📂 feature-name/ + │ │ ├── 📂 components/ # Feature UI pieces + │ │ ├── 📂 pages/ # Route-level pages (when used) + │ │ ├── 📂 models/ # Feature-local *.model.ts types + │ │ ├── 📂 mappers/ # Feature API ↔ domain mappers + │ │ ├── 📂 services/ # Feature HTTP / facade services + │ │ ├── 📂 store/ # Feature NGXS state (actions, model, state, selectors) + │ │ ├── 📂 enums/ # Feature enums + │ │ ├── 📂 constants/ # Feature constants + │ │ ├── feature.routes.ts # Feature routes + │ │ └── feature.component.ts # Feature shell / entry component + │ │ + │ ├── 📂 core/ # App-wide infrastructure + │ │ ├── 📂 components/ # Shell UI (header, banners, …) + │ │ ├── 📂 services/ # Global services + │ │ ├── 📂 store/ # Core NGXS state (user, emails, …) + │ │ ├── 📂 models/ # Core config / routing types + │ │ ├── 📂 guards/ + │ │ ├── 📂 interceptors/ + │ │ ├── 📂 helpers/ + │ │ └── 📂 provider/ + │ │ + │ ├── 📂 shared/ # Cross-feature reusable code + │ │ ├── 📂 components/ # Shared UI + │ │ ├── 📂 directives/ + │ │ ├── 📂 pipes/ + │ │ ├── 📂 services/ # Shared HTTP / helpers + │ │ ├── 📂 stores/ # Shared NGXS domains + │ │ ├── 📂 models/ # Shared domain + JSON:API models + │ │ ├── 📂 mappers/ # Shared mappers + │ │ ├── 📂 enums/ + │ │ ├── 📂 guards/ + │ │ └── 📂 helpers/ + │ │ + │ ├── app.component.ts + │ ├── app.config.ts + │ ├── app.config.server.ts # SSR app config + │ ├── app.routes.ts + │ └── app.routes.server.ts # SSR routes │ - ├── 📂 core/ # Base module for global services, components, and state - │ ├── 📂 services/ # Global services (API, Auth, LocalStorage) - │ ├── 📂 components/ # Global components (Header, Footer, Sidebar) - │ ├── 📂 store/ # Core state management (Auth, Settings, Router) - │ ├── core.module.ts # Optional, but must have a provider for core. - │ - ├── 📂 shared/ # Shared module for common components, directives, pipes, and services - │ ├── 📂 ui/ # Shared UI components (Button, Input, Modal), or wrappers for 3rd party - │ ├── 📂 directives/ # Shared Directives (ClickOutside, Draggable) - │ ├── 📂 pipes/ # Shared Pipes (Filter, Sort, Format) - │ ├── 📂 services/ # Services, Facades for shared logic (Http, LocalStorage) - │ ├── 📂 store/ # Shared State management (Settings, Theme, Language) - │ - ├── app.routes.ts # General Entry point for routing - ├── main.ts # Providers Setup and Bootstrap - ├── package.json # Dependencies and Scripts + ├── 📂 assets/ + ├── 📂 environments/ + ├── 📂 styles/ + ├── 📂 testing/ # Test helpers, mocks, builders (@testing/*) + ├── main.ts # Browser bootstrap + ├── main.server.ts # SSR bootstrap + ├── server.ts # Express / SSR server entry + └── index.html +``` + +--- +## 📋 Models and mappers + +- Types live in `*.model.ts` files (interfaces/types, not classes). +- Shared catalog: `shared/models//` with optional `*-json-api.model.ts` twins. +- Feature-local types: `features//models/`. +- Mappers convert JSON:API ↔ domain at the service boundary. + +See [Models Conventions](./models.md). + +--- + +## 🗃️ State + +- Shared domains: `shared/stores//` +- Feature domains: `features//store/` +- Core domains: `core/store/` + +See [NGXS State Management](./ngxs.md). --- -``` ## 🚀 Dynamic File Generation (Schematics) -Use Angular CLI to generate new feature components, services, and modules. +Use Angular CLI for scaffolding: ```sh ng generate component feature-name/components/new-component +``` ### 📌 Other Schematics: -| **Entity** | **Command** | -|--------------|----------------------------------------------| -| 📌 **Service** | `ng g s feature-name/services/new-service` | -| 📦 **Module** | `ng g m feature-name` | -| 🔐 **Guard** | `ng g g feature-name/guards/auth-guard` | -| 🔄 **Pipe** | `ng g p shared/pipes/currency-format` | -| ✨ **Directive** | `ng g d shared/directives/highlight` | - - -``` +| **Entity** | **Command** | +| ---------------- | ------------------------------------------ | +| 📌 **Service** | `ng g s feature-name/services/new-service` | +| 🔐 **Guard** | `ng g g feature-name/guards/auth-guard` | +| 🔄 **Pipe** | `ng g p shared/pipes/currency-format` | +| ✨ **Directive** | `ng g d shared/directives/highlight` | diff --git a/docs/models.md b/docs/models.md new file mode 100644 index 000000000..ac08f49e8 --- /dev/null +++ b/docs/models.md @@ -0,0 +1,94 @@ +# Models Conventions + +## Purpose + +Models are TypeScript interfaces and types that describe data shapes. They are not classes. Mapping from API wire format to app domain happens in mappers. + +## Layers + +``` +JSON:API (*-json-api.model.ts) → mapper → domain model → store (*StateModel) → UI +``` + +| Layer | Role | Naming | +| -------- | ------------------------------------------------------ | ----------------------------------------------------- | +| JSON:API | Wire/DTO shapes from the backend (`snake_case` fields) | `*JsonApi`, `*DataJsonApi`, `*ResponseJsonApi` | +| Domain | App-facing shapes (`camelCase` fields) | Prefer descriptive names; `*Model` suffix is optional | +| State | NGXS slice shape | Always `*StateModel` | +| Form | Reactive form value shapes | `*Form`, `*FormGroup` | + +Keep JSON:API types in services and mappers. Prefer domain models in stores, selectors, and components. + +## Locations + +| Location | Use for | +| ---------------------------------------- | ------------------------------------------------------------------------------------------- | +| `src/app/shared/models//` | Cross-feature domain + JSON:API types | +| `src/app/shared/models/common/json-api/` | Shared JSON:API primitives (`JsonApiResource`, `ItemResponse`, `ListResponse`, links, meta) | +| `src/app/features//models/` | Feature-local UI, form, and API types | +| `src/app/**/store*/**/*.model.ts` | Colocated NGXS state models | +| `src/app/core/models/` | App-wide config and core types | + +## File naming + +- Domain / general: `kebab-case.model.ts` +- JSON:API twin: `kebab-case-json-api.model.ts` (dash, not dot) +- Forms: `kebab-case-form.model.ts` +- One concern per file when practical; group related exports in the same domain folder + +Examples: + +- `user.model.ts` + `user-json-api.model.ts` +- `configured-addon.model.ts` + `configured-addon-json-api.model.ts` + +## Symbol naming + +- Domain: `UserModel`, `InstitutionUser`, `RegistrationCard` (suffix `Model` is encouraged for primary entities, not required for every interface) +- JSON:API: always end with `JsonApi` (e.g. `UserDataJsonApi`, `UserResponseJsonApi`) +- State: always `*StateModel` (e.g. `AddonsStateModel`, `SubjectsStateModel`) +- Do not put snake_case field names on domain models; map them in the mapper + +## Mappers + +- Live in `shared/mappers/` or `features//mappers/` +- Convert `*JsonApi` → domain models (and domain → request payloads when needed) +- Prefer static mapper classes (`UserMapper.fromUserGetResponse`) or focused `mapX` functions; keep one style within a feature + +## Imports + +Prefer the `@osf/` alias for app code: + +```ts +import { UserModel } from '@osf/shared/models/user/user.model'; +import { UserDataJsonApi } from '@osf/shared/models/user/user-json-api.model'; +``` + +Feature barrels are optional. When a feature has `models/index.ts`, import from the barrel: + +```ts +import { ModeratorModel } from '@osf/features/moderation/models'; +``` + +Otherwise import the file path directly. Do not mix `@osf/shared/models/...` and `@shared/models/...` in new code — use `@osf/...`. + +## State models + +Colocate with the store. Compose domain types inside `AsyncStateModel` / `AsyncStateWithTotalCount`: + +```ts +export interface FilesStateModel { + files: AsyncStateModel; +} +``` + +See [NGXS docs](./ngxs.md) for store layout and async state shape. + +## Checklist for new models + +1. Put shared types under `shared/models//`, feature-only types under `features//models/` +2. Add a `*-json-api.model.ts` twin only when typing an HTTP payload/response +3. Use interfaces/types, not classes +4. Keep domain fields camelCase; leave snake_case in JSON:API types +5. Map at the service/mapper boundary before storing or rendering +6. Name store interfaces `*StateModel` +7. Import via `@osf/...` diff --git a/docs/ngxs.md b/docs/ngxs.md index 583394c53..cb3df1551 100644 --- a/docs/ngxs.md +++ b/docs/ngxs.md @@ -34,7 +34,7 @@ The goal of using NGXS is to centralize and streamline the handling of applicati ### Diagram -[![OSF NGRX Diagram](./assets/osf-ngxs-diagram.png)](./assets/osf-ngxs-diagram.png) +[![OSF NGXS Diagram](./assets/osf-ngxs-diagram.png)](./assets/osf-ngxs-diagram.png) --- @@ -45,44 +45,51 @@ Typical NGXS-related files are organized as follows: ``` src/app/shared/stores/ └── addons/ - ├── addons.actions.ts # All action definitions - ├── addons.model.ts # Interfaces & data model - ├── addons.state.ts # State implementation - ├── addons.selectors.ts # Reusable selectors + ├── addons.actions.ts # Action definitions + ├── addons.model.ts # State interface (*StateModel) and defaults + ├── addons.state.ts # State implementation + ├── addons.selectors.ts # Selectors ``` ``` src/app/shared/services/ └── addons/ - ├── addons.service.ts # External API calls + ├── addons.service.ts # External API calls (map JSON:API → domain) ``` +Feature stores follow the same file set under `features//store/`. Core stores live under `core/store/`. + --- ## State Models -The OSF Angular project follows a consistent NGXS state model structure to ensure clarity, predictability, and alignment across all features. The recommended shape for each domain-specific state is as follows: +State interfaces are named `*StateModel` and live in the colocated `*.model.ts` file. They are TypeScript interfaces (not classes). Domain entity types come from `shared/models` or feature `models/` — see [Models Conventions](./models.md). -1. Domain state pattern: +Use `AsyncStateModel` (and `AsyncStateWithTotalCount` when a total count is needed) from `shared/models/store/`: ```ts -domain: { - data: [], // Array of typed model data (e.g., Project[], User[]) - isLoading: false, // Indicates if data retrieval (GET) is in progress - isSubmitting: false, // Indicates if data submission (POST/PUT/DELETE) is in progress - error: null, // Captures error messages from failed HTTP requests +export interface AsyncStateModel { + data: T; + isLoading: boolean; + isSubmitting?: boolean; + error: string | null; } ``` -2. `data` holds the strongly typed collection of entities defined by the feature's interface or model class. - -3. `isLoading` is a signal used to inform the component and template layer that a read or fetch operation is currently pending. +Example store shape: -4. `isSubmitting` signals that a write operation (form submission, update, delete, etc.) is currently in progress. +```ts +export interface FilesStateModel { + files: AsyncStateModel; +} +``` -5. `error` stores error state information (commonly strings or structured error objects) that result from failed service interactions. This can be displayed in UI or logged for debugging. +1. `data` holds strongly typed domain data (not raw JSON:API payloads when a domain model exists). +2. `isLoading` indicates a read/fetch is in progress. +3. `isSubmitting` indicates a write (create/update/delete) is in progress. +4. `error` stores a failed request message for UI or logging. -Each domain state should be minimal, normalized, and scoped to its specific feature, mirroring the structure and shape of the corresponding OSF backend API response. +Each domain state should be minimal and scoped to its feature. --- @@ -96,12 +103,13 @@ Each domain state should be minimal, normalized, and scoped to its specific feat ## Testing -- [Testing Strategy](docs/testing.md) -- [NGXS State Testing Strategy](docs/testing.md#ngxs-state-testing-strategy) +- [Testing Strategy](./testing.md) +- [NGXS State Testing Strategy](./testing.md#15-testing-ngxs-state) --- ## Documentation -Refer to the official NGXS documentation for full API details and advanced usage: -[https://www.ngxs.io/docs](https://www.ngxs.io/docs) +- [Models Conventions](./models.md) +- [Folder Structure](./arch.md) +- Official NGXS docs: [https://www.ngxs.io/docs](https://www.ngxs.io/docs) diff --git a/src/app/core/constants/nav-items.constant.ts b/src/app/core/constants/nav-items.constant.ts index 6ec9ee652..1a4f3b833 100644 --- a/src/app/core/constants/nav-items.constant.ts +++ b/src/app/core/constants/nav-items.constant.ts @@ -380,7 +380,7 @@ export const MENU_ITEMS: CustomMenuItem[] = [ routerLink: '/settings/profile', label: 'navigation.profileSettings', visible: true, - routerLinkActiveOptions: { exact: true }, + routerLinkActiveOptions: { exact: false }, }, { id: 'settings-account', diff --git a/src/app/features/admin-institutions/components/filters-section/filters-section.component.ts b/src/app/features/admin-institutions/components/filters-section/filters-section.component.ts index 5ec51efde..836ee5c46 100644 --- a/src/app/features/admin-institutions/components/filters-section/filters-section.component.ts +++ b/src/app/features/admin-institutions/components/filters-section/filters-section.component.ts @@ -10,7 +10,7 @@ import { ChangeDetectionStrategy, Component, model } from '@angular/core'; import { FilterChipsComponent } from '@osf/shared/components/filter-chips/filter-chips.component'; import { SearchFiltersComponent } from '@osf/shared/components/search-filters/search-filters.component'; import { DiscoverableFilter } from '@osf/shared/models/search/discoverable-filter.model'; -import { FilterOptionRemoved } from '@osf/shared/models/search/filter-option-removed'; +import { FilterOptionRemoved } from '@osf/shared/models/search/filter-option-removed.model'; import { FilterOptionSelected } from '@osf/shared/models/search/filter-option-selected.model'; import { FilterOptionsSearchText } from '@osf/shared/models/search/filter-options-search-text.model'; import { diff --git a/src/app/features/admin-institutions/mappers/institution-departments.mapper.ts b/src/app/features/admin-institutions/mappers/institution-departments.mapper.ts index 22b0f07df..aced15a9c 100644 --- a/src/app/features/admin-institutions/mappers/institution-departments.mapper.ts +++ b/src/app/features/admin-institutions/mappers/institution-departments.mapper.ts @@ -1,15 +1,10 @@ -import { - InstitutionDepartment, - InstitutionDepartmentDataJsonApi, - InstitutionDepartmentsJsonApi, -} from '@osf/features/admin-institutions/models'; +import { InstitutionDepartment, InstitutionDepartmentDataJsonApi, InstitutionDepartmentsJsonApi } from '../models'; export function mapInstitutionDepartments(jsonApiData: InstitutionDepartmentsJsonApi): InstitutionDepartment[] { return jsonApiData.data.map((department: InstitutionDepartmentDataJsonApi) => ({ id: department.id, name: department.attributes.name, numberOfUsers: department.attributes.number_of_users, - selfLink: department.links.self, })); } @@ -18,6 +13,5 @@ export function mapInstitutionDepartment(department: InstitutionDepartmentDataJs id: department.id, name: department.attributes.name, numberOfUsers: department.attributes.number_of_users, - selfLink: department.links.self, }; } diff --git a/src/app/features/admin-institutions/mappers/institution-summary-index.mapper.ts b/src/app/features/admin-institutions/mappers/institution-summary-index.mapper.ts index 14c55de85..6f40631a6 100644 --- a/src/app/features/admin-institutions/mappers/institution-summary-index.mapper.ts +++ b/src/app/features/admin-institutions/mappers/institution-summary-index.mapper.ts @@ -3,9 +3,15 @@ import { InstitutionIndexValueSearchIncludedJsonApi, InstitutionSearchFilter, InstitutionSearchResultCountJsonApi, -} from '@osf/features/admin-institutions/models'; +} from '../models'; + +export function mapIndexCardResults( + included: InstitutionIndexValueSearchIncludedJsonApi[] | undefined +): InstitutionSearchFilter[] { + if (!included) { + return []; + } -export function mapIndexCardResults(included: InstitutionIndexValueSearchIncludedJsonApi[]): InstitutionSearchFilter[] { const indexCardMap = included.reduce( (acc, item) => { if (item.type === 'index-card') { diff --git a/src/app/features/admin-institutions/mappers/institution-users.mapper.ts b/src/app/features/admin-institutions/mappers/institution-users.mapper.ts index 7f9785b2e..d79f8f198 100644 --- a/src/app/features/admin-institutions/mappers/institution-users.mapper.ts +++ b/src/app/features/admin-institutions/mappers/institution-users.mapper.ts @@ -3,7 +3,7 @@ import { InstitutionUser, InstitutionUserDataJsonApi, InstitutionUsersJsonApi } export function mapInstitutionUsers(jsonApiData: InstitutionUsersJsonApi): InstitutionUser[] { return jsonApiData.data.map((user: InstitutionUserDataJsonApi) => ({ id: user.id, - userId: user.relationships.user.data.id, + userId: user.relationships?.user?.data?.id ?? '', userName: user.attributes.user_name, department: user.attributes.department, orcidId: user.attributes.orcid_id, diff --git a/src/app/features/admin-institutions/models/institution-department.model.ts b/src/app/features/admin-institutions/models/institution-department.model.ts index f0341bd1d..9119aa3e6 100644 --- a/src/app/features/admin-institutions/models/institution-department.model.ts +++ b/src/app/features/admin-institutions/models/institution-department.model.ts @@ -2,5 +2,4 @@ export interface InstitutionDepartment { id: string; name: string; numberOfUsers: number; - selfLink: string; } diff --git a/src/app/features/admin-institutions/models/institution-departments-json-api.model.ts b/src/app/features/admin-institutions/models/institution-departments-json-api.model.ts index b44db76b7..cf15fb815 100644 --- a/src/app/features/admin-institutions/models/institution-departments-json-api.model.ts +++ b/src/app/features/admin-institutions/models/institution-departments-json-api.model.ts @@ -1,19 +1,14 @@ -export interface InstitutionDepartmentAttributesJsonApi { - name: string; - number_of_users: number; -} +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; -export interface InstitutionDepartmentLinksJsonApi { - self: string; -} +export type InstitutionDepartmentsJsonApi = ListResponse; -export interface InstitutionDepartmentDataJsonApi { - id: string; - type: 'institution-departments'; - attributes: InstitutionDepartmentAttributesJsonApi; - links: InstitutionDepartmentLinksJsonApi; -} +export type InstitutionDepartmentDataJsonApi = JsonApiResource< + 'institution-departments', + InstitutionDepartmentAttributesJsonApi +>; -export interface InstitutionDepartmentsJsonApi { - data: InstitutionDepartmentDataJsonApi[]; +interface InstitutionDepartmentAttributesJsonApi { + name: string; + number_of_users: number; } diff --git a/src/app/features/admin-institutions/models/institution-index-value-search-json-api.model.ts b/src/app/features/admin-institutions/models/institution-index-value-search-json-api.model.ts index b76c8e348..1d0767823 100644 --- a/src/app/features/admin-institutions/models/institution-index-value-search-json-api.model.ts +++ b/src/app/features/admin-institutions/models/institution-index-value-search-json-api.model.ts @@ -1,42 +1,37 @@ -import { JsonApiResponse } from '@shared/models/common/json-api.model'; +import { ToOneRelData } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { JsonApiResponse } from '@osf/shared/models/common/json-api/responses.model'; -export interface InstitutionSearchResultCountJsonApi { - attributes: { - cardSearchResultCount: number; - }; - id: string; - type: string; - relationships: { - indexCard: { - data: { - id: string; - type: string; - }; - }; - }; +export type InstitutionIndexValueSearchIncludedJsonApi = + | InstitutionSearchResultCountJsonApi + | InstitutionIndexCardFilterJsonApi; + +export type InstitutionIndexValueSearchJsonApi = JsonApiResponse; +export type InstitutionIndexCardFilterJsonApi = JsonApiResource<'index-card', InstitutionIndexCardAttributesJsonApi>; + +interface InstitutionIndexCardResourceMetadataJsonApi { + '@id': string; + displayLabel?: { '@value': string }[]; + name: { '@value': string }[]; } -export interface InstitutionIndexCardFilterJsonApi { - attributes: { - resourceIdentifier: string[]; - resourceMetadata: { - displayLabel: { '@value': string }[]; - '@id': string; - name: { '@value': string }[]; - }; - }; - id: string; - type: string; +interface InstitutionIndexCardAttributesJsonApi { + resourceIdentifier: string[]; + resourceMetadata: InstitutionIndexCardResourceMetadataJsonApi; } -export type InstitutionIndexValueSearchIncludedJsonApi = - | InstitutionSearchResultCountJsonApi - | InstitutionIndexCardFilterJsonApi; +interface InstitutionSearchResultAttributesJsonApi { + cardSearchResultCount: number; +} + +interface InstitutionSearchResultRelationshipsJsonApi { + indexCard: ToOneRelData; +} -export interface InstitutionIndexValueSearchJsonApi extends JsonApiResponse< - null, - InstitutionIndexValueSearchIncludedJsonApi[] +export interface InstitutionSearchResultCountJsonApi extends Omit< + JsonApiResource, + 'attributes' > { - data: null; - included: InstitutionIndexValueSearchIncludedJsonApi[]; + attributes?: InstitutionSearchResultAttributesJsonApi; + relationships: InstitutionSearchResultRelationshipsJsonApi; } diff --git a/src/app/features/admin-institutions/models/institution-summary-metrics-json-api.model.ts b/src/app/features/admin-institutions/models/institution-summary-metrics-json-api.model.ts index c418e98ac..77a62bad9 100644 --- a/src/app/features/admin-institutions/models/institution-summary-metrics-json-api.model.ts +++ b/src/app/features/admin-institutions/models/institution-summary-metrics-json-api.model.ts @@ -1,3 +1,13 @@ +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; + +export type InstitutionSummaryMetricsJsonApi = ItemResponse; + +export type InstitutionSummaryMetricsDataJsonApi = JsonApiResource< + 'institution-summary-metrics', + InstitutionSummaryMetricsAttributesJsonApi +>; + export interface InstitutionSummaryMetricsAttributesJsonApi { report_yearmonth: string; user_count: number; @@ -11,36 +21,3 @@ export interface InstitutionSummaryMetricsAttributesJsonApi { monthly_logged_in_user_count: number; monthly_active_user_count: number; } - -export interface InstitutionSummaryMetricsRelationshipsJsonApi { - user: { - data: null; - }; - institution: { - links: { - related: { - href: string; - meta: Record; - }; - }; - data: { - id: string; - type: 'institutions'; - }; - }; -} - -export interface InstitutionSummaryMetricsDataJsonApi { - id: string; - type: 'institution-summary-metrics'; - attributes: InstitutionSummaryMetricsAttributesJsonApi; - relationships: InstitutionSummaryMetricsRelationshipsJsonApi; - links: Record; -} - -export interface InstitutionSummaryMetricsJsonApi { - data: InstitutionSummaryMetricsDataJsonApi; - meta: { - version: string; - }; -} diff --git a/src/app/features/admin-institutions/models/institution-users-json-api.model.ts b/src/app/features/admin-institutions/models/institution-users-json-api.model.ts index dd07ec1eb..b35559cee 100644 --- a/src/app/features/admin-institutions/models/institution-users-json-api.model.ts +++ b/src/app/features/admin-institutions/models/institution-users-json-api.model.ts @@ -1,6 +1,17 @@ -import { MetaJsonApi } from '@osf/shared/models/common/json-api.model'; +import { ToOneRel } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; -export interface InstitutionUserAttributesJsonApi { +export type InstitutionUsersJsonApi = ListResponse; + +export interface InstitutionUserDataJsonApi extends JsonApiResource< + 'institution-users', + InstitutionUserAttributesJsonApi +> { + relationships: InstitutionUserRelationshipsJsonApi; +} + +interface InstitutionUserAttributesJsonApi { user_name: string; department: string | null; orcid_id: string | null; @@ -18,29 +29,7 @@ export interface InstitutionUserAttributesJsonApi { storage_byte_count: number; } -export interface InstitutionUserRelationshipDataJsonApi { - id: string; - type: string; -} - -export interface InstitutionUserRelationshipJsonApi { - data: InstitutionUserRelationshipDataJsonApi; -} - -export interface InstitutionUserRelationshipsJsonApi { - user: InstitutionUserRelationshipJsonApi; - institution: InstitutionUserRelationshipJsonApi; -} - -export interface InstitutionUserDataJsonApi { - id: string; - type: 'institution-users'; - attributes: InstitutionUserAttributesJsonApi; - relationships: InstitutionUserRelationshipsJsonApi; - links: Record; -} - -export interface InstitutionUsersJsonApi { - data: InstitutionUserDataJsonApi[]; - meta: MetaJsonApi; +interface InstitutionUserRelationshipsJsonApi { + user: ToOneRel<'user'>; + institution: ToOneRel<'institution'>; } diff --git a/src/app/features/admin-institutions/models/send-message-json-api.model.ts b/src/app/features/admin-institutions/models/send-message-json-api.model.ts index e561865da..70d03b304 100644 --- a/src/app/features/admin-institutions/models/send-message-json-api.model.ts +++ b/src/app/features/admin-institutions/models/send-message-json-api.model.ts @@ -1,12 +1,13 @@ -export interface SendMessageResponseJsonApi { - data: { - id: string; - type: string; - attributes: { - message_text: string; - message_type: string; - bcc_sender: boolean; - reply_to: boolean; - }; - }; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; + +export type SendMessageResponseJsonApi = ItemResponse; + +export type SendMessageDataJsonApi = JsonApiResource<'send-message', SendMessageAttributesJsonApi>; + +interface SendMessageAttributesJsonApi { + message_text: string; + message_type: string; + bcc_sender: boolean; + reply_to: boolean; } diff --git a/src/app/features/admin-institutions/store/institutions-admin.model.ts b/src/app/features/admin-institutions/store/institutions-admin.model.ts index 239078b99..e1f994297 100644 --- a/src/app/features/admin-institutions/store/institutions-admin.model.ts +++ b/src/app/features/admin-institutions/store/institutions-admin.model.ts @@ -4,7 +4,7 @@ import { AsyncStateWithTotalCount } from '@osf/shared/models/store/async-state-w import { InstitutionDepartment, InstitutionSearchFilter, InstitutionSummaryMetrics, InstitutionUser } from '../models'; -export interface InstitutionsAdminModel { +export interface InstitutionsAdminStateModel { departments: AsyncStateModel; summaryMetrics: AsyncStateModel; hasOsfAddonSearch: AsyncStateModel; @@ -14,7 +14,7 @@ export interface InstitutionsAdminModel { institution: AsyncStateModel; } -export const INSTITUTIONS_ADMIN_STATE_DEFAULTS: InstitutionsAdminModel = { +export const INSTITUTIONS_ADMIN_STATE_DEFAULTS: InstitutionsAdminStateModel = { departments: { data: [], isLoading: false, error: null }, summaryMetrics: { data: {} as InstitutionSummaryMetrics, isLoading: false, error: null }, hasOsfAddonSearch: { data: [], isLoading: false, error: null }, diff --git a/src/app/features/admin-institutions/store/institutions-admin.selectors.ts b/src/app/features/admin-institutions/store/institutions-admin.selectors.ts index 721901e4d..a92c98d40 100644 --- a/src/app/features/admin-institutions/store/institutions-admin.selectors.ts +++ b/src/app/features/admin-institutions/store/institutions-admin.selectors.ts @@ -4,82 +4,82 @@ import { Institution } from '@osf/shared/models/institutions/institutions.model' import { InstitutionDepartment, InstitutionSearchFilter, InstitutionSummaryMetrics, InstitutionUser } from '../models'; -import { InstitutionsAdminModel } from './institutions-admin.model'; +import { InstitutionsAdminStateModel } from './institutions-admin.model'; import { InstitutionsAdminState } from './institutions-admin.state'; export class InstitutionsAdminSelectors { @Selector([InstitutionsAdminState]) - static getDepartments(state: InstitutionsAdminModel): InstitutionDepartment[] { + static getDepartments(state: InstitutionsAdminStateModel): InstitutionDepartment[] { return state.departments.data; } @Selector([InstitutionsAdminState]) - static getDepartmentsLoading(state: InstitutionsAdminModel): boolean { + static getDepartmentsLoading(state: InstitutionsAdminStateModel): boolean { return state.departments.isLoading; } @Selector([InstitutionsAdminState]) - static getSummaryMetrics(state: InstitutionsAdminModel): InstitutionSummaryMetrics { + static getSummaryMetrics(state: InstitutionsAdminStateModel): InstitutionSummaryMetrics { return state.summaryMetrics.data; } @Selector([InstitutionsAdminState]) - static getSummaryMetricsLoading(state: InstitutionsAdminModel): boolean { + static getSummaryMetricsLoading(state: InstitutionsAdminStateModel): boolean { return state.summaryMetrics.isLoading; } @Selector([InstitutionsAdminState]) - static getHasOsfAddonSearch(state: InstitutionsAdminModel): InstitutionSearchFilter[] { + static getHasOsfAddonSearch(state: InstitutionsAdminStateModel): InstitutionSearchFilter[] { return state.hasOsfAddonSearch.data; } @Selector([InstitutionsAdminState]) - static getHasOsfAddonSearchLoading(state: InstitutionsAdminModel): boolean { + static getHasOsfAddonSearchLoading(state: InstitutionsAdminStateModel): boolean { return state.hasOsfAddonSearch.isLoading; } @Selector([InstitutionsAdminState]) - static getStorageRegionSearch(state: InstitutionsAdminModel): InstitutionSearchFilter[] { + static getStorageRegionSearch(state: InstitutionsAdminStateModel): InstitutionSearchFilter[] { return state.storageRegionSearch.data; } @Selector([InstitutionsAdminState]) - static getStorageRegionSearchLoading(state: InstitutionsAdminModel): boolean { + static getStorageRegionSearchLoading(state: InstitutionsAdminStateModel): boolean { return state.storageRegionSearch.isLoading; } @Selector([InstitutionsAdminState]) - static getSearchResults(state: InstitutionsAdminModel): InstitutionSearchFilter[] { + static getSearchResults(state: InstitutionsAdminStateModel): InstitutionSearchFilter[] { return state.searchResults.data; } @Selector([InstitutionsAdminState]) - static getSearchResultsLoading(state: InstitutionsAdminModel): boolean { + static getSearchResultsLoading(state: InstitutionsAdminStateModel): boolean { return state.searchResults.isLoading; } @Selector([InstitutionsAdminState]) - static getUsers(state: InstitutionsAdminModel): InstitutionUser[] { + static getUsers(state: InstitutionsAdminStateModel): InstitutionUser[] { return state.users.data; } @Selector([InstitutionsAdminState]) - static getUsersLoading(state: InstitutionsAdminModel): boolean { + static getUsersLoading(state: InstitutionsAdminStateModel): boolean { return state.users.isLoading; } @Selector([InstitutionsAdminState]) - static getUsersTotalCount(state: InstitutionsAdminModel): number { + static getUsersTotalCount(state: InstitutionsAdminStateModel): number { return state.users.totalCount; } @Selector([InstitutionsAdminState]) - static getInstitution(state: InstitutionsAdminModel): Institution { + static getInstitution(state: InstitutionsAdminStateModel): Institution { return state.institution.data; } @Selector([InstitutionsAdminState]) - static getInstitutionLoading(state: InstitutionsAdminModel): boolean { + static getInstitutionLoading(state: InstitutionsAdminStateModel): boolean { return state.institution.isLoading; } } diff --git a/src/app/features/admin-institutions/store/institutions-admin.state.ts b/src/app/features/admin-institutions/store/institutions-admin.state.ts index 8285669a1..db763a6be 100644 --- a/src/app/features/admin-institutions/store/institutions-admin.state.ts +++ b/src/app/features/admin-institutions/store/institutions-admin.state.ts @@ -22,9 +22,9 @@ import { RequestProjectAccess, SendUserMessage, } from './institutions-admin.actions'; -import { INSTITUTIONS_ADMIN_STATE_DEFAULTS, InstitutionsAdminModel } from './institutions-admin.model'; +import { INSTITUTIONS_ADMIN_STATE_DEFAULTS, InstitutionsAdminStateModel } from './institutions-admin.model'; -@State({ +@State({ name: 'institutionsAdmin', defaults: INSTITUTIONS_ADMIN_STATE_DEFAULTS, }) @@ -34,7 +34,7 @@ export class InstitutionsAdminState { private readonly institutionsAdminService = inject(InstitutionsAdminService); @Action(FetchInstitutionById) - fetchInstitutionById(ctx: StateContext, action: FetchInstitutionById) { + fetchInstitutionById(ctx: StateContext, action: FetchInstitutionById) { ctx.patchState({ institution: { data: {} as Institution, isLoading: true, error: null } }); return this.institutionsService.getInstitutionById(action.institutionId).pipe( @@ -50,7 +50,7 @@ export class InstitutionsAdminState { } @Action(FetchInstitutionDepartments) - fetchDepartments(ctx: StateContext) { + fetchDepartments(ctx: StateContext) { const state = ctx.getState(); ctx.patchState({ departments: { ...state.departments, isLoading: true, error: null }, @@ -69,7 +69,7 @@ export class InstitutionsAdminState { } @Action(FetchInstitutionSummaryMetrics) - fetchSummaryMetrics(ctx: StateContext) { + fetchSummaryMetrics(ctx: StateContext) { const state = ctx.getState(); ctx.patchState({ summaryMetrics: { ...state.summaryMetrics, isLoading: true, error: null }, @@ -87,7 +87,7 @@ export class InstitutionsAdminState { } @Action(FetchInstitutionSearchResults) - fetchSearchResults(ctx: StateContext, action: FetchInstitutionSearchResults) { + fetchSearchResults(ctx: StateContext, action: FetchInstitutionSearchResults) { const state = ctx.getState(); ctx.patchState({ searchResults: { ...state.searchResults, isLoading: true, error: null }, @@ -107,7 +107,7 @@ export class InstitutionsAdminState { } @Action(FetchHasOsfAddonSearch) - fetchHasOsfAddonSearch(ctx: StateContext) { + fetchHasOsfAddonSearch(ctx: StateContext) { const state = ctx.getState(); ctx.patchState({ hasOsfAddonSearch: { ...state.hasOsfAddonSearch, isLoading: true, error: null }, @@ -125,7 +125,7 @@ export class InstitutionsAdminState { } @Action(FetchStorageRegionSearch) - fetchStorageRegionSearch(ctx: StateContext) { + fetchStorageRegionSearch(ctx: StateContext) { const state = ctx.getState(); ctx.patchState({ storageRegionSearch: { ...state.storageRegionSearch, isLoading: true, error: null }, @@ -143,7 +143,7 @@ export class InstitutionsAdminState { } @Action(FetchInstitutionUsers) - fetchUsers(ctx: StateContext, action: FetchInstitutionUsers) { + fetchUsers(ctx: StateContext, action: FetchInstitutionUsers) { const state = ctx.getState(); ctx.patchState({ users: { ...state.users, isLoading: true, error: null }, @@ -162,7 +162,7 @@ export class InstitutionsAdminState { } @Action(SendUserMessage) - sendUserMessage(_: StateContext, action: SendUserMessage) { + sendUserMessage(_: StateContext, action: SendUserMessage) { return this.institutionsAdminService .sendMessage({ userId: action.userId, @@ -175,7 +175,7 @@ export class InstitutionsAdminState { } @Action(RequestProjectAccess) - requestProjectAccess(_: StateContext, action: RequestProjectAccess) { + requestProjectAccess(_: StateContext, action: RequestProjectAccess) { return this.institutionsAdminService .requestProjectAccess(action.payload) .pipe(catchError((error) => throwError(() => error))); diff --git a/src/app/features/analytics/mappers/related-counts.mapper.ts b/src/app/features/analytics/mappers/related-counts.mapper.ts index 89ba90f4f..caef745eb 100644 --- a/src/app/features/analytics/mappers/related-counts.mapper.ts +++ b/src/app/features/analytics/mappers/related-counts.mapper.ts @@ -1,13 +1,13 @@ -import { RelatedCountsGetResponse, RelatedCountsModel } from '../models'; +import { RelatedCountsModel, RelatedCountsResponseJsonApi } from '../models'; export class RelatedCountsMapper { - static fromResponse(response: RelatedCountsGetResponse): RelatedCountsModel { + static fromResponse(response: RelatedCountsResponseJsonApi): RelatedCountsModel { return { id: response.data.id, isPublic: response.data.attributes.public, - forksCount: response.data.relationships.forks?.links.related.meta.count || 0, - linksToCount: response.data.relationships.linked_by_nodes?.links.related.meta.count || 0, - templateCount: response.meta.templated_by_count || 0, + forksCount: response.data.relationships.forks?.links?.related?.meta?.count ?? 0, + linksToCount: response.data.relationships.linked_by_nodes?.links?.related?.meta?.count ?? 0, + templateCount: response.meta?.templated_by_count ?? 0, }; } } diff --git a/src/app/features/analytics/models/node-analytics-json-api.model.ts b/src/app/features/analytics/models/node-analytics-json-api.model.ts index e06297531..6fdf9f7be 100644 --- a/src/app/features/analytics/models/node-analytics-json-api.model.ts +++ b/src/app/features/analytics/models/node-analytics-json-api.model.ts @@ -1,33 +1,30 @@ -import { ResponseDataJsonApi } from '@osf/shared/models/common/json-api.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; -export type NodeAnalyticsResponseJsonApi = ResponseDataJsonApi; +export type NodeAnalyticsResponseJsonApi = ItemResponse; -export interface NodeAnalyticsDataJsonApi { - id: string; - type: 'node-analytics'; - attributes: NodeAnalyticsAttributesJsonApi; -} +export type NodeAnalyticsDataJsonApi = JsonApiResource<'node-analytics', NodeAnalyticsAttributesJsonApi>; -export interface NodeAnalyticsAttributesJsonApi { +interface NodeAnalyticsAttributesJsonApi { popular_pages: PopularPageJsonApi[]; unique_visits: UniqueVisitJsonApi[]; time_of_day: TimeOfDayJsonApi[]; referer_domain: RefererDomainJsonApi[]; } -export interface PopularPageJsonApi { +interface PopularPageJsonApi { path: string; route: string; title: string; count: number; } -export interface UniqueVisitJsonApi { +interface UniqueVisitJsonApi { date: string; count: number; } -export interface TimeOfDayJsonApi { +interface TimeOfDayJsonApi { hour: number; count: number; } diff --git a/src/app/features/analytics/models/related-counts-json-api.model.ts b/src/app/features/analytics/models/related-counts-json-api.model.ts index f51b9acf4..2914a1545 100644 --- a/src/app/features/analytics/models/related-counts-json-api.model.ts +++ b/src/app/features/analytics/models/related-counts-json-api.model.ts @@ -1,39 +1,21 @@ -export interface RelatedCountsGetResponse { - data: RelatedCountsDataResponse; - meta: MetaGetResponse; -} - -interface MetaGetResponse { - templated_by_count: number; -} - -interface RelatedCountsDataResponse { - id: string; - attributes: RelatedCountsAttributes; - relationships: RelationshipsResponse; -} +import { RelatedCountRel } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; +import { BaseNodeAttributesJsonApi } from '@osf/shared/models/nodes/base-node-attributes-json-api.model'; -interface RelatedCountsAttributes { - public: boolean; -} - -interface RelationshipsResponse { - forks: Relationship; - linked_by_nodes: Relationship; -} +export type RelatedCountsResponseJsonApi = ItemResponse & { + meta: RelatedCountsResponseMetaJsonApi; +}; -interface Relationship { - links: Links; +interface RelatedCountsDataJsonApi extends JsonApiResource<'related-counts', BaseNodeAttributesJsonApi> { + relationships: RelatedCountsRelationshipsJsonApi; } -interface Links { - related: RelatedLink; +interface RelatedCountsRelationshipsJsonApi { + forks?: RelatedCountRel; + linked_by_nodes?: RelatedCountRel; } -interface RelatedLink { - meta: MetaCount; -} - -interface MetaCount { - count: number; +interface RelatedCountsResponseMetaJsonApi { + templated_by_count: number; } diff --git a/src/app/features/analytics/services/resource-analytics.service.ts b/src/app/features/analytics/services/resource-analytics.service.ts index 96a7e1bf6..019de928c 100644 --- a/src/app/features/analytics/services/resource-analytics.service.ts +++ b/src/app/features/analytics/services/resource-analytics.service.ts @@ -7,7 +7,7 @@ import { AnalyticsMetricsMapper, RelatedCountsMapper } from '@osf/features/analy import { NodeAnalyticsModel, NodeAnalyticsResponseJsonApi, - RelatedCountsGetResponse, + RelatedCountsResponseJsonApi, } from '@osf/features/analytics/models'; import { ResourceType } from '@osf/shared/enums/resource-type.enum'; import { JsonApiService } from '@osf/shared/services/json-api.service'; @@ -41,7 +41,7 @@ export class ResourceAnalyticsService { const url = `${this.apiDomainUrl}/v2/${resourcePath}/${resourceId}/?related_counts=true`; return this.jsonApiService - .get(url) + .get(url) .pipe(map((response) => RelatedCountsMapper.fromResponse(response))); } } diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.spec.ts b/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.spec.ts index 8ca0ac448..976162229 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.spec.ts +++ b/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.spec.ts @@ -11,7 +11,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CreateCollectionSubmission } from '@osf/features/collections/store/add-to-collection/add-to-collection.actions'; import { CedarMetadataAttributes, - CedarMetadataRecordData, + CedarMetadataRecordModel, CedarRecordDataBinding, } from '@osf/features/metadata/models'; import { CreateCedarMetadataRecord, UpdateCedarMetadataRecord } from '@osf/features/metadata/store'; @@ -33,13 +33,13 @@ const MOCK_CEDAR_DATA: CedarRecordDataBinding = { isPublished: true, }; -const MOCK_EXISTING_CEDAR_RECORD: CedarMetadataRecordData = { +const MOCK_EXISTING_CEDAR_RECORD: CedarMetadataRecordModel = { id: 'cedar-record-1', - attributes: { metadata: {} as CedarMetadataAttributes, is_published: true }, - relationships: { - template: { data: { type: 'cedar-metadata-templates', id: 'template-1' } }, - target: { data: { type: 'nodes', id: 'project-1' } }, - }, + metadata: {} as CedarMetadataAttributes, + isPublished: true, + templateId: 'template-1', + targetId: 'project-1', + schemaName: 'Test Schema', }; describe('AddToCollectionConfirmationDialogComponent', () => { @@ -53,7 +53,7 @@ describe('AddToCollectionConfirmationDialogComponent', () => { payload?: CollectionSubmissionPayload; project?: { id: string; isPublic: boolean }; cedarData?: CedarRecordDataBinding | null; - existingCedarRecord?: CedarMetadataRecordData | null; + existingCedarRecord?: CedarMetadataRecordModel | null; }; }; diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.ts b/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.ts index 52aef57c0..b7be98cef 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.ts +++ b/src/app/features/collections/components/add-to-collection/add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component.ts @@ -11,7 +11,7 @@ import { ChangeDetectionStrategy, Component, DestroyRef, inject, signal } from ' import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { CreateCollectionSubmission } from '@osf/features/collections/store/add-to-collection/add-to-collection.actions'; -import { CedarMetadataRecordData, CedarRecordDataBinding } from '@osf/features/metadata/models'; +import { CedarMetadataRecordModel, CedarRecordDataBinding } from '@osf/features/metadata/models'; import { CreateCedarMetadataRecord, UpdateCedarMetadataRecord } from '@osf/features/metadata/store'; import { UpdateProjectPublicStatus } from '@osf/features/project/overview/store'; import { ResourceType } from '@osf/shared/enums/resource-type.enum'; @@ -26,12 +26,15 @@ import { ToastService } from '@osf/shared/services/toast.service'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class AddToCollectionConfirmationDialogComponent { - private toastService = inject(ToastService); - dialogRef = inject(DynamicDialogRef); - config = inject(DynamicDialogConfig); - destroyRef = inject(DestroyRef); - isSubmitting = signal(false); - actions = createDispatchMap({ + readonly dialogRef = inject(DynamicDialogRef); + + private readonly toastService = inject(ToastService); + private readonly config = inject(DynamicDialogConfig); + private readonly destroyRef = inject(DestroyRef); + + readonly isSubmitting = signal(false); + + private readonly actions = createDispatchMap({ createCollectionSubmission: CreateCollectionSubmission, updateProjectPublicStatus: UpdateProjectPublicStatus, createCedarRecord: CreateCedarMetadataRecord, @@ -42,7 +45,7 @@ export class AddToCollectionConfirmationDialogComponent { const payload = this.config.data.payload; const project = this.config.data.project as ProjectModel | null | undefined; const cedarData = this.config.data.cedarData as CedarRecordDataBinding | null | undefined; - const existingCedarRecord = this.config.data.existingCedarRecord as CedarMetadataRecordData | null | undefined; + const existingCedarRecord = this.config.data.existingCedarRecord as CedarMetadataRecordModel | null | undefined; if (!payload || !project) return; diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts b/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts index 7c78df5cb..2d9b08390 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts +++ b/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts @@ -23,7 +23,7 @@ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { UserSelectors } from '@core/store/user'; -import { CedarMetadataRecordData, CedarRecordDataBinding } from '@osf/features/metadata/models'; +import { CedarMetadataRecordModel, CedarRecordDataBinding } from '@osf/features/metadata/models'; import { CreateCedarMetadataRecord, GetCedarMetadataRecords, @@ -117,11 +117,11 @@ export class AddToCollectionComponent implements CanDeactivateComponent { isCollectionMetadataDisabled = computed( () => !this.selectedProject() || !this.projectMetadataSaved() || !this.projectContributorsSaved() ); - existingCedarRecord = computed(() => { + existingCedarRecord = computed(() => { const records = this.cedarRecords(); const templateId = this.requiredMetadataTemplate()?.id; if (!records?.length || !templateId) return null; - return records.find((r) => r.relationships?.template?.data?.id === templateId) ?? null; + return records.find((r) => r.templateId === templateId) ?? null; }); readonly actions = createDispatchMap({ diff --git a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html index 0b345920a..0a07bac19 100644 --- a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html +++ b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html @@ -17,7 +17,7 @@

{{ 'collections.addToCollection.collectionMetadata' | translate }}

} @@ -44,7 +44,7 @@

{{ 'collections.addToCollection.collectionMetadata' | translate }}

{ let component: CollectionMetadataStepComponent; let fixture: ComponentFixture; + const mockCedarTemplate = MOCK_CEDAR_METADATA_TEMPLATE; + function setup( options: { - cedarTemplate?: CedarMetadataDataTemplateJsonApi | null; - existingCedarRecord?: CedarMetadataRecordData | null; + cedarTemplate?: CedarMetadataTemplateModel | null; + existingCedarRecord?: CedarMetadataRecordModel | null; stepperActiveValue?: number; targetStepValue?: number; isDisabled?: boolean; @@ -88,13 +89,13 @@ describe('CollectionMetadataStepComponent', () => { }); it('should accept cedar template', () => { - setup({ cedarTemplate: MOCK_CEDAR_TEMPLATE }); + setup({ cedarTemplate: mockCedarTemplate }); - expect(component.cedarTemplate()).toEqual(MOCK_CEDAR_TEMPLATE); + expect(component.cedarTemplate()).toEqual(mockCedarTemplate); }); it('should handle discard changes without existing record', () => { - setup({ cedarTemplate: MOCK_CEDAR_TEMPLATE }); + setup({ cedarTemplate: mockCedarTemplate }); component.cedarFormData.set({ field: 'value' }); component.collectionMetadataSaved.set(true); @@ -107,7 +108,7 @@ describe('CollectionMetadataStepComponent', () => { it('should discard cedar changes to existing record metadata', () => { setup({ - cedarTemplate: MOCK_CEDAR_TEMPLATE, + cedarTemplate: mockCedarTemplate, existingCedarRecord: MOCK_CEDAR_RECORD, }); @@ -122,7 +123,7 @@ describe('CollectionMetadataStepComponent', () => { it('should populate cedarFormData from existingCedarRecord', () => { setup({ - cedarTemplate: MOCK_CEDAR_TEMPLATE, + cedarTemplate: mockCedarTemplate, existingCedarRecord: MOCK_CEDAR_RECORD, }); @@ -131,7 +132,7 @@ describe('CollectionMetadataStepComponent', () => { it('should not overwrite cedarFormData from API when metadata is already saved locally', () => { setup({ - cedarTemplate: MOCK_CEDAR_TEMPLATE, + cedarTemplate: mockCedarTemplate, existingCedarRecord: MOCK_CEDAR_RECORD, }); @@ -140,10 +141,7 @@ describe('CollectionMetadataStepComponent', () => { fixture.componentRef.setInput('existingCedarRecord', { ...MOCK_CEDAR_RECORD, - attributes: { - ...MOCK_CEDAR_RECORD.attributes, - metadata: { field: 'api' } as unknown as CedarMetadataRecordData['attributes']['metadata'], - }, + metadata: { field: 'api' } as unknown as CedarMetadataRecordModel['metadata'], }); fixture.detectChanges(); @@ -151,7 +149,7 @@ describe('CollectionMetadataStepComponent', () => { }); it('should not emit cedarDataSaved when handleSaveCedarMetadata is called without editor', () => { - setup({ cedarTemplate: MOCK_CEDAR_TEMPLATE }); + setup({ cedarTemplate: mockCedarTemplate }); const cedarDataSavedSpy = vi.spyOn(component.cedarDataSaved, 'emit'); const stepChangeSpy = vi.spyOn(component.stepChange, 'emit'); @@ -163,7 +161,7 @@ describe('CollectionMetadataStepComponent', () => { }); it('should handle onCedarChange event', () => { - setup({ cedarTemplate: MOCK_CEDAR_TEMPLATE }); + setup({ cedarTemplate: mockCedarTemplate }); const mockMetadata = { field: 'changed' }; const mockEditor = { currentMetadata: mockMetadata }; @@ -177,7 +175,7 @@ describe('CollectionMetadataStepComponent', () => { }); it('should not update cedarFormData when onCedarChange has no currentMetadata', () => { - setup({ cedarTemplate: MOCK_CEDAR_TEMPLATE }); + setup({ cedarTemplate: mockCedarTemplate }); const mockEvent = new CustomEvent('change', {}); const mockEditor = {}; @@ -192,7 +190,7 @@ describe('CollectionMetadataStepComponent', () => { }); it('should not emit cedarDataSaved without template', () => { - setup({ cedarTemplate: MOCK_CEDAR_TEMPLATE }); + setup({ cedarTemplate: mockCedarTemplate }); fixture.componentRef.setInput('cedarTemplate', null); fixture.detectChanges(); diff --git a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts index 0a1934b02..d383908ec 100644 --- a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts +++ b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts @@ -23,8 +23,8 @@ import { AddToCollectionSteps } from '@osf/features/collections/enums'; import { CEDAR_CONFIG, CEDAR_VIEWER_CONFIG } from '@osf/features/metadata/constants'; import { CedarEditorElement, - CedarMetadataDataTemplateJsonApi, - CedarMetadataRecordData, + CedarMetadataRecordModel, + CedarMetadataTemplateModel, CedarRecordDataBinding, } from '@osf/features/metadata/models'; @@ -41,8 +41,8 @@ export class CollectionMetadataStepComponent { stepperActiveValue = input.required(); targetStepValue = input.required(); isDisabled = input.required(); - cedarTemplate = input(null); - existingCedarRecord = input(null); + cedarTemplate = input(null); + existingCedarRecord = input(null); stepChange = output(); cedarDataSaved = output(); @@ -68,7 +68,7 @@ export class CollectionMetadataStepComponent { handleDiscardChanges() { const record = this.existingCedarRecord(); - this.cedarFormData.set(record?.attributes?.metadata ? (record.attributes.metadata as Record) : {}); + this.cedarFormData.set(record?.metadata ? (record.metadata as Record) : {}); this.syncCedarInstance(this.cedarEditor()?.nativeElement); this.collectionMetadataSaved.set(false); } @@ -111,8 +111,8 @@ export class CollectionMetadataStepComponent { if (this.collectionMetadataSaved()) return; const record = this.existingCedarRecord(); - if (record?.attributes?.metadata) { - this.cedarFormData.set(record.attributes.metadata as Record); + if (record?.metadata) { + this.cedarFormData.set(record.metadata as Record); } }); @@ -122,7 +122,7 @@ export class CollectionMetadataStepComponent { const record = this.existingCedarRecord(); const saved = this.collectionMetadataSaved(); - if (!record?.attributes?.metadata && !saved) return; + if (!record?.metadata && !saved) return; this.syncCedarInstance(this.cedarEditor()?.nativeElement); }); diff --git a/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts b/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts index 42e4f6c3c..bc5426251 100644 --- a/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts +++ b/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts @@ -38,38 +38,37 @@ const MOCK_COLLECTION_PROVIDER_WITH_TEMPLATE = { ...MOCK_COLLECTION_PROVIDER, requiredMetadataTemplate: { id: 'template-1', - type: 'cedar-metadata-templates' as const, - attributes: { - schema_name: 'Test', - cedar_id: 'cedar-1', - template: { - '@id': 'https://repo.metadatacenter.org/templates/test', - '@type': 'https://schema.metadatacenter.org/core/Template', - type: 'object', - title: 'Test', - description: '', - $schema: 'http://json-schema.org/draft-04/schema', - '@context': {} as never, - required: [], - properties: { - '@context': { - properties: { - field1: { enum: ['https://schema.metadatacenter.org/properties/test-field-uuid'] }, - }, - }, - field1: { - '@type': 'https://schema.metadatacenter.org/core/TemplateField', - _valueConstraints: { - literals: [{ label: 'Option A' }, { label: 'Option B' }], - }, + schemaName: 'Test', + isForCollections: false, + active: true, + cedarId: 'cedar-1', + template: { + '@id': 'https://repo.metadatacenter.org/templates/test', + '@type': 'https://schema.metadatacenter.org/core/Template', + type: 'object', + title: 'Test', + description: '', + $schema: 'http://json-schema.org/draft-04/schema', + '@context': {} as never, + required: [], + properties: { + '@context': { + properties: { + field1: { enum: ['https://schema.metadatacenter.org/properties/test-field-uuid'] }, }, }, - _ui: { - order: ['field1'], - propertyLabels: { field1: 'Field One' }, - propertyDescriptions: {}, + field1: { + '@type': 'https://schema.metadatacenter.org/core/TemplateField', + _valueConstraints: { + literals: [{ label: 'Option A' }, { label: 'Option B' }], + }, }, }, + _ui: { + order: ['field1'], + propertyLabels: { field1: 'Field One' }, + propertyDescriptions: {}, + }, }, }, }; diff --git a/src/app/features/collections/components/collections-discover/collections-discover.component.ts b/src/app/features/collections/components/collections-discover/collections-discover.component.ts index 39fc8245d..73098fc71 100644 --- a/src/app/features/collections/components/collections-discover/collections-discover.component.ts +++ b/src/app/features/collections/components/collections-discover/collections-discover.component.ts @@ -113,10 +113,8 @@ export class CollectionsDiscoverComponent { this.actions.setDefaultFilterValue('isPartOfCollection', collectionIri); - if (provider.requiredMetadataTemplate?.attributes?.template) { - const extraFilters = CedarTemplateFilterMapper.fromTemplate( - provider.requiredMetadataTemplate.attributes.template - ); + if (provider.requiredMetadataTemplate?.template) { + const extraFilters = CedarTemplateFilterMapper.fromTemplate(provider.requiredMetadataTemplate.template); this.actions.setExtraFilters(extraFilters); } diff --git a/src/app/features/collections/models/collection-license-json-api.model.ts b/src/app/features/collections/models/collection-license-json-api.model.ts index 10f98c57e..13072e4ed 100644 --- a/src/app/features/collections/models/collection-license-json-api.model.ts +++ b/src/app/features/collections/models/collection-license-json-api.model.ts @@ -1,22 +1,24 @@ +import { ToOneRelData } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { DataResponse } from '@osf/shared/models/common/json-api/responses.model'; import { LicenseRecordJsonApi } from '@osf/shared/models/license/licenses-json-api.model'; -export interface CollectionSubmissionMetadataPayloadJsonApi { - data: { - type: 'nodes'; - id: string; - relationships: { - license: { - data: { - id: string; - type: string; - }; - }; - }; - attributes: { - node_license?: LicenseRecordJsonApi; - title?: string; - description?: string; - tags?: string[]; - }; - }; +export type CollectionSubmissionMetadataPayloadJsonApi = DataResponse; + +interface CollectionSubmissionMetadataDataJsonApi extends JsonApiResource< + 'nodes', + CollectionSubmissionMetadataAttributesJsonApi +> { + relationships: CollectionSubmissionMetadataRelationshipsJsonApi; +} + +interface CollectionSubmissionMetadataAttributesJsonApi { + node_license?: LicenseRecordJsonApi; + title?: string; + description?: string; + tags?: string[]; +} + +interface CollectionSubmissionMetadataRelationshipsJsonApi { + license: ToOneRelData<'licenses'>; } diff --git a/src/app/features/collections/models/project-metadata-form.model.ts b/src/app/features/collections/models/project-metadata-form.model.ts index 464ca263a..c21bdf81f 100644 --- a/src/app/features/collections/models/project-metadata-form.model.ts +++ b/src/app/features/collections/models/project-metadata-form.model.ts @@ -1,8 +1,9 @@ import { FormControl } from '@angular/forms'; -import { ProjectMetadataFormControls } from '@osf/features/collections/enums'; import { LicenseModel } from '@osf/shared/models/license/license.model'; +import { ProjectMetadataFormControls } from '../enums'; + export interface ProjectMetadataForm { [ProjectMetadataFormControls.Title]: FormControl; [ProjectMetadataFormControls.Description]: FormControl; diff --git a/src/app/features/collections/store/add-to-collection/add-to-collection.model.ts b/src/app/features/collections/store/add-to-collection/add-to-collection.model.ts index ba47d319d..bbdc0823a 100644 --- a/src/app/features/collections/store/add-to-collection/add-to-collection.model.ts +++ b/src/app/features/collections/store/add-to-collection/add-to-collection.model.ts @@ -1,4 +1,4 @@ -import { CollectionProjectSubmission } from '@osf/shared/models/collections/collections.model'; +import { CollectionProjectSubmission } from '@osf/shared/models/collections/collection-submissions.model'; import { LicenseModel } from '@shared/models/license/license.model'; import { AsyncStateModel } from '@shared/models/store/async-state.model'; diff --git a/src/app/features/files/mappers/file-custom-metadata.mapper.ts b/src/app/features/files/mappers/file-custom-metadata.mapper.ts index 1292bd004..233dd0a2c 100644 --- a/src/app/features/files/mappers/file-custom-metadata.mapper.ts +++ b/src/app/features/files/mappers/file-custom-metadata.mapper.ts @@ -1,10 +1,9 @@ -import { ApiData } from '@osf/shared/models/common/json-api.model'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; import { OsfFileCustomMetadata } from '../models/file-custom-metadata.model'; -import { FileCustomMetadata } from '../models/get-file-metadata-response.model'; +import { FileCustomMetadataDataJsonApi } from '../models/file-metadata-response.model'; -export function MapFileCustomMetadata(data: ApiData): OsfFileCustomMetadata { +export function MapFileCustomMetadata(data: FileCustomMetadataDataJsonApi): OsfFileCustomMetadata { return { id: data.id, description: replaceBadEncodedChars(data.attributes.description), diff --git a/src/app/features/files/mappers/file-revision.mapper.ts b/src/app/features/files/mappers/file-revision.mapper.ts index 34c6b08a4..83268af3a 100644 --- a/src/app/features/files/mappers/file-revision.mapper.ts +++ b/src/app/features/files/mappers/file-revision.mapper.ts @@ -1,14 +1,11 @@ -import { ApiData } from '@osf/shared/models/common/json-api.model'; - import { OsfFileRevision } from '../models/file-revisions.model'; -import { FileRevisionJsonApi } from '../models/get-file-revisions-response.model'; +import { FileRevisionDataJsonApi } from '../models/file-revisions-response.model'; -export function MapFileRevision(data: ApiData[]): OsfFileRevision[] { - const revision = data.map((revision) => ({ +export function MapFileRevision(data: FileRevisionDataJsonApi[]): OsfFileRevision[] { + return data.map((revision) => ({ downloads: revision.attributes.extra.downloads ?? 0, hashes: { md5: revision.attributes.extra.hashes?.md5, sha256: revision.attributes.extra.hashes?.sha256 }, dateTime: new Date(revision.attributes.modified_utc), version: revision.attributes.version, })); - return revision; } diff --git a/src/app/features/files/mappers/resource-metadata.mapper.ts b/src/app/features/files/mappers/resource-metadata.mapper.ts index 5fc0e6fc0..827c3e92b 100644 --- a/src/app/features/files/mappers/resource-metadata.mapper.ts +++ b/src/app/features/files/mappers/resource-metadata.mapper.ts @@ -2,12 +2,12 @@ import { IdentifiersMapper } from '@osf/shared/mappers/identifiers.mapper'; import { ResourceMetadata } from '@osf/shared/models/resource-metadata.model'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; -import { GetResourceCustomMetadataResponse } from '../models/get-resource-custom-metadata-response.model'; -import { GetResourceShortInfoResponse } from '../models/get-resource-short-info-response.model'; +import { NodeShortInfoResponse } from '../models/node-short-info-response.model'; +import { ResourceCustomMetadataResponse } from '../models/resource-custom-metadata-response.model'; export function MapResourceMetadata( - shortInfo: GetResourceShortInfoResponse, - customMetadata: GetResourceCustomMetadataResponse + shortInfo: NodeShortInfoResponse, + customMetadata: ResourceCustomMetadataResponse ): ResourceMetadata { return { title: replaceBadEncodedChars(shortInfo.data.attributes.title), diff --git a/src/app/features/files/models/file-metadata-response.model.ts b/src/app/features/files/models/file-metadata-response.model.ts new file mode 100644 index 000000000..925861218 --- /dev/null +++ b/src/app/features/files/models/file-metadata-response.model.ts @@ -0,0 +1,16 @@ +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; + +export type FileMetadataResponse = ItemResponse; + +export type FileCustomMetadataDataJsonApi = JsonApiResource< + 'custom_file_metadata_records', + FileCustomMetadataAttributesJsonApi +>; + +interface FileCustomMetadataAttributesJsonApi { + description: string; + language: string; + resource_type_general: string; + title: string; +} diff --git a/src/app/features/files/models/file-revisions-response.model.ts b/src/app/features/files/models/file-revisions-response.model.ts new file mode 100644 index 000000000..0ee38dddd --- /dev/null +++ b/src/app/features/files/models/file-revisions-response.model.ts @@ -0,0 +1,23 @@ +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { DataResponse } from '@osf/shared/models/common/json-api/responses.model'; + +export type FileRevisionsResponse = DataResponse; + +export type FileRevisionDataJsonApi = JsonApiResource; + +interface FileRevisionAttributesJsonApi { + extra: FileRevisionExtraJsonApi; + modified: string; + modified_utc: string; + version: string; +} + +interface FileRevisionExtraJsonApi { + downloads: number; + hashes: FileRevisionHashesJsonApi; +} + +interface FileRevisionHashesJsonApi { + md5: string; + sha256: string; +} diff --git a/src/app/features/files/models/get-custom-metadata-response.model.ts b/src/app/features/files/models/get-custom-metadata-response.model.ts deleted file mode 100644 index 4420eff6e..000000000 --- a/src/app/features/files/models/get-custom-metadata-response.model.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ApiData, JsonApiResponse } from '@osf/shared/models/common/json-api.model'; - -export type GetCustomMetadataResponse = JsonApiResponse, null>; - -export interface MetadataEmbedResponse { - custom_metadata: JsonApiResponse< - ApiData< - { - language: string; - resource_type_general: string; - funders: { - funder_name: string; - funder_identifier: string; - funder_identifier_type: string; - award_number: string; - award_uri: string; - award_title: string; - }[]; - }, - null, - null, - null - >, - null - >; -} diff --git a/src/app/features/files/models/get-file-metadata-response.model.ts b/src/app/features/files/models/get-file-metadata-response.model.ts deleted file mode 100644 index 7f0662855..000000000 --- a/src/app/features/files/models/get-file-metadata-response.model.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ApiData, JsonApiResponse } from '@osf/shared/models/common/json-api.model'; - -export type GetFileMetadataResponse = JsonApiResponse, null>; - -export interface FileCustomMetadata { - language: string; - resource_type_general: string; - title: string; - description: string; -} diff --git a/src/app/features/files/models/get-file-revisions-response.model.ts b/src/app/features/files/models/get-file-revisions-response.model.ts deleted file mode 100644 index 04de4bc59..000000000 --- a/src/app/features/files/models/get-file-revisions-response.model.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiData, JsonApiResponse } from '@osf/shared/models/common/json-api.model'; - -export interface FileRevisionJsonApi { - extra: { - downloads: number; - hashes: { - md5: string; - sha256: string; - }; - }; - version: string; - modified: string; - modified_utc: string; -} - -export type GetFileRevisionsResponse = JsonApiResponse[], null>; diff --git a/src/app/features/files/models/get-resource-custom-metadata-response.model.ts b/src/app/features/files/models/get-resource-custom-metadata-response.model.ts deleted file mode 100644 index 10e121cfa..000000000 --- a/src/app/features/files/models/get-resource-custom-metadata-response.model.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ApiData, JsonApiResponse } from '@osf/shared/models/common/json-api.model'; - -export type GetResourceCustomMetadataResponse = JsonApiResponse< - ApiData, - null ->; - -export interface ResourceMetadataEmbedResponse { - custom_metadata: JsonApiResponse< - ApiData< - { - language: string; - resource_type_general: string; - funders: { - funder_name: string; - funder_identifier: string; - funder_identifier_type: string; - award_number: string; - award_uri: string; - award_title: string; - }[]; - }, - null, - null, - null - >, - null - >; -} diff --git a/src/app/features/files/models/get-resource-short-info-response.model.ts b/src/app/features/files/models/get-resource-short-info-response.model.ts deleted file mode 100644 index 831a33f76..000000000 --- a/src/app/features/files/models/get-resource-short-info-response.model.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ApiData, JsonApiResponse } from '@osf/shared/models/common/json-api.model'; -import { IdentifiersResponseJsonApi } from '@osf/shared/models/identifiers/identifier-json-api.model'; - -export type GetResourceShortInfoResponse = JsonApiResponse< - ApiData< - { - title: string; - description: string; - date_created: string; - date_modified: string; - }, - { identifiers: IdentifiersResponseJsonApi }, - null, - null - >, - null ->; diff --git a/src/app/features/files/models/get-short-info-response.model.ts b/src/app/features/files/models/get-short-info-response.model.ts deleted file mode 100644 index 2fd10f273..000000000 --- a/src/app/features/files/models/get-short-info-response.model.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ApiData, JsonApiResponse } from '@osf/shared/models/common/json-api.model'; -import { IdentifiersResponseJsonApi } from '@osf/shared/models/identifiers/identifier-json-api.model'; - -export type GetShortInfoResponse = JsonApiResponse< - ApiData< - { - title: string; - description: string; - date_created: string; - date_modified: string; - }, - { identifiers: IdentifiersResponseJsonApi }, - null, - null - >, - null ->; diff --git a/src/app/features/files/models/node-short-info-response.model.ts b/src/app/features/files/models/node-short-info-response.model.ts new file mode 100644 index 000000000..13a248d8e --- /dev/null +++ b/src/app/features/files/models/node-short-info-response.model.ts @@ -0,0 +1,20 @@ +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; +import { IdentifiersResponseJsonApi } from '@osf/shared/models/identifiers/identifier-json-api.model'; + +export type NodeShortInfoResponse = ItemResponse; + +export interface NodeShortInfoDataJsonApi extends JsonApiResource { + embeds?: NodeShortInfoEmbedsJsonApi; +} + +interface NodeShortInfoAttributesJsonApi { + date_created: string; + date_modified: string; + description: string; + title: string; +} + +interface NodeShortInfoEmbedsJsonApi { + identifiers: IdentifiersResponseJsonApi; +} diff --git a/src/app/features/files/models/resource-custom-metadata-response.model.ts b/src/app/features/files/models/resource-custom-metadata-response.model.ts new file mode 100644 index 000000000..debe5a66b --- /dev/null +++ b/src/app/features/files/models/resource-custom-metadata-response.model.ts @@ -0,0 +1,30 @@ +import { Embed } from '@osf/shared/models/common/json-api/embeds.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse } from '@osf/shared/models/common/json-api/responses.model'; + +export type ResourceCustomMetadataResponse = ItemResponse; + +export interface ResourceCustomMetadataGuidDataJsonApi extends JsonApiResource<'guids', Record> { + embeds: ResourceCustomMetadataEmbedsJsonApi; +} + +interface ResourceCustomMetadataEmbedsJsonApi { + custom_metadata: Embed; +} + +type CustomMetadataDataJsonApi = JsonApiResource<'custom-metadata-records', CustomMetadataAttributesJsonApi>; + +interface CustomMetadataAttributesJsonApi { + funders: CustomMetadataFunderJsonApi[]; + language: string; + resource_type_general: string; +} + +interface CustomMetadataFunderJsonApi { + award_number: string; + award_title: string; + award_uri: string; + funder_identifier: string; + funder_identifier_type: string; + funder_name: string; +} diff --git a/src/app/features/files/pages/file-detail/file-detail.component.spec.ts b/src/app/features/files/pages/file-detail/file-detail.component.spec.ts index 6cb497816..275f16279 100644 --- a/src/app/features/files/pages/file-detail/file-detail.component.spec.ts +++ b/src/app/features/files/pages/file-detail/file-detail.component.spec.ts @@ -8,10 +8,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { - CedarMetadataDataTemplateJsonApi, - CedarMetadataRecordData, + CedarMetadataRecordModel, + CedarMetadataTemplateModel, CedarRecordDataBinding, - CedarTemplate, } from '@osf/features/metadata/models'; import { GetCedarMetadataRecords, MetadataSelectors, UpdateCedarMetadataRecord } from '@osf/features/metadata/store'; import { LoadingSpinnerComponent } from '@osf/shared/components/loading-spinner/loading-spinner.component'; @@ -349,26 +348,22 @@ describe('FileDetailComponent', () => { }); it('should select cedar record when metadata tab matches cedar record id', () => { - const cedarRecord = { + const cedarRecord: CedarMetadataRecordModel = { id: 'rec-1', - attributes: { - metadata: {}, - is_published: false, - }, - relationships: { - template: { data: { type: 'cedar-metadata-templates', id: 'tpl-1' } }, - target: { data: { type: 'files', id: 'file-1' } }, - }, - } as CedarMetadataRecordData; - const cedarTemplate = { + metadata: {} as CedarMetadataRecordModel['metadata'], + isPublished: false, + templateId: 'tpl-1', + targetId: 'file-1', + schemaName: 'Schema A', + }; + const cedarTemplate: CedarMetadataTemplateModel = { id: 'tpl-1', - type: 'cedar-metadata-templates', - attributes: { - schema_name: 'Schema A', - cedar_id: 'cedar', - template: {} as CedarTemplate, - }, - } as CedarMetadataDataTemplateJsonApi; + schemaName: 'Schema A', + isForCollections: false, + active: true, + cedarId: 'cedar', + template: {} as CedarMetadataTemplateModel['template'], + }; setup({ selectorOverrides: [ { selector: MetadataSelectors.getCedarRecords, value: [cedarRecord] }, @@ -383,26 +378,22 @@ describe('FileDetailComponent', () => { }); it('should dispatch cedar update and refresh records on cedar form submit', async () => { - const cedarRecord = { + const cedarRecord: CedarMetadataRecordModel = { id: 'rec-1', - attributes: { - metadata: {}, - is_published: false, - }, - relationships: { - template: { data: { type: 'cedar-metadata-templates', id: 'tpl-1' } }, - target: { data: { type: 'files', id: 'file-1' } }, - }, - } as CedarMetadataRecordData; - const cedarTemplate = { + metadata: {} as CedarMetadataRecordModel['metadata'], + isPublished: false, + templateId: 'tpl-1', + targetId: 'file-1', + schemaName: 'Schema A', + }; + const cedarTemplate: CedarMetadataTemplateModel = { id: 'tpl-1', - type: 'cedar-metadata-templates', - attributes: { - schema_name: 'Schema A', - cedar_id: 'cedar', - template: {} as CedarTemplate, - }, - } as CedarMetadataDataTemplateJsonApi; + schemaName: 'Schema A', + isForCollections: false, + active: true, + cedarId: 'cedar', + template: {} as CedarMetadataTemplateModel['template'], + }; setup({ selectorOverrides: [ { selector: MetadataSelectors.getCedarRecords, value: [cedarRecord] }, diff --git a/src/app/features/files/pages/file-detail/file-detail.component.ts b/src/app/features/files/pages/file-detail/file-detail.component.ts index 4e1591d22..e9d72d80d 100644 --- a/src/app/features/files/pages/file-detail/file-detail.component.ts +++ b/src/app/features/files/pages/file-detail/file-detail.component.ts @@ -24,8 +24,8 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { - CedarMetadataDataTemplateJsonApi, - CedarMetadataRecordData, + CedarMetadataRecordModel, + CedarMetadataTemplateModel, CedarRecordDataBinding, } from '@osf/features/metadata/models'; import { @@ -182,8 +182,8 @@ export class FileDetailComponent implements OnDestroy { selectedMetadataTab = signal('osf'); - selectedCedarRecord = signal(null); - selectedCedarTemplate = signal(null); + selectedCedarRecord = signal(null); + selectedCedarTemplate = signal(null); cedarFormReadonly = signal(true); canManageFileActions = computed(() => !this.isAnonymous() && !this.hasViewOnly() && this.hasWriteAccess()); @@ -394,7 +394,7 @@ export class FileDetailComponent implements OnDestroy { this.selectedCedarRecord.set(record); this.cedarFormReadonly.set(true); - const templateId = record.relationships?.template?.data?.id; + const templateId = record.templateId; if (templateId && templates?.data) { const template = templates.data.find((t) => t.id === templateId); @@ -419,7 +419,7 @@ export class FileDetailComponent implements OnDestroy { const cedarTabs = records?.map((record) => ({ id: record.id || '', - label: record.embeds?.template?.data?.attributes?.schema_name || `Record ${record.id}`, + label: record.schemaName || `Record ${record.id}`, type: MetadataResourceEnum.CEDAR, })) || []; diff --git a/src/app/features/files/store/files.state.ts b/src/app/features/files/store/files.state.ts index 9b84843c5..5813dfce0 100644 --- a/src/app/features/files/store/files.state.ts +++ b/src/app/features/files/store/files.state.ts @@ -159,11 +159,11 @@ export class FilesState { ctx.patchState({ tags: { ...state.tags, isLoading: true, error: null } }); return this.filesService.getFileTarget(action.fileGuid).pipe( - tap(({ file, meta }) => { + tap(({ file, isAnonymous }) => { ctx.patchState({ openedFile: { data: file, isLoading: false, error: null }, tags: { data: file.tags, isLoading: false, error: null }, - isAnonymous: meta?.anonymous ?? false, + isAnonymous, }); }), catchError((error) => handleSectionError(ctx, 'openedFile', error)) @@ -267,11 +267,11 @@ export class FilesState { tap((response) => ctx.patchState({ rootFolders: { - data: response.files, + data: response.data, isLoading: false, error: null, }, - isAnonymous: response.meta?.anonymous ?? false, + isAnonymous: response.isAnonymous, }) ), catchError((error) => handleSectionError(ctx, 'rootFolders', error)) @@ -287,11 +287,11 @@ export class FilesState { tap((response) => ctx.patchState({ moveDialogRootFolders: { - data: response.files, + data: response.data, isLoading: false, error: null, }, - isAnonymous: response.meta?.anonymous ?? false, + isAnonymous: response.isAnonymous, }) ), catchError((error) => handleSectionError(ctx, 'moveDialogRootFolders', error)) diff --git a/src/app/features/home/pages/dashboard/dashboard.component.ts b/src/app/features/home/pages/dashboard/dashboard.component.ts index 63ec0f106..886c670fc 100644 --- a/src/app/features/home/pages/dashboard/dashboard.component.ts +++ b/src/app/features/home/pages/dashboard/dashboard.component.ts @@ -23,7 +23,7 @@ import { SearchInputComponent } from '@osf/shared/components/search-input/search import { SubHeaderComponent } from '@osf/shared/components/sub-header/sub-header.component'; import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants/default-table-params.constants'; import { SortOrder } from '@osf/shared/enums/sort-order.enum'; -import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources.model'; +import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources-item.model'; import { MyResourcesSearchFilters } from '@osf/shared/models/my-resources/my-resources-search-filters.model'; import { CustomDialogService } from '@osf/shared/services/custom-dialog.service'; import { ProjectRedirectDialogService } from '@osf/shared/services/project-redirect-dialog.service'; diff --git a/src/app/features/meetings/mappers/meetings.mapper.ts b/src/app/features/meetings/mappers/meetings.mapper.ts index f967aa4bb..bd34d187f 100644 --- a/src/app/features/meetings/mappers/meetings.mapper.ts +++ b/src/app/features/meetings/mappers/meetings.mapper.ts @@ -1,15 +1,15 @@ -import { ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; import { - MeetingGetResponseJsonApi, - MeetingSubmissionGetResponseJsonApi, + MeetingDataJsonApi, + MeetingsListResponseJsonApi, + MeetingSubmissionsListResponseJsonApi, MeetingSubmissionsWithPaging, MeetingsWithPaging, } from '../models'; export class MeetingsMapper { - static fromMeetingsGetResponse(response: ResponseJsonApi): MeetingsWithPaging { + static fromMeetingsGetResponse(response: MeetingsListResponseJsonApi): MeetingsWithPaging { return { data: response.data.map((item) => ({ id: item.id, @@ -24,7 +24,7 @@ export class MeetingsMapper { } static fromMeetingSubmissionGetResponse( - response: ResponseJsonApi + response: MeetingSubmissionsListResponseJsonApi ): MeetingSubmissionsWithPaging { return { data: response.data.map((item) => ({ @@ -40,7 +40,7 @@ export class MeetingsMapper { }; } - static fromMeetingGetResponse(response: MeetingGetResponseJsonApi) { + static fromMeetingGetResponse(response: MeetingDataJsonApi) { return { id: response.id, name: response.attributes.name, diff --git a/src/app/features/meetings/models/meetings-json-api.model.ts b/src/app/features/meetings/models/meetings-json-api.model.ts index b2d77d7e1..c66e38c64 100644 --- a/src/app/features/meetings/models/meetings-json-api.model.ts +++ b/src/app/features/meetings/models/meetings-json-api.model.ts @@ -1,28 +1,36 @@ import { NumberOrNull, StringOrNull } from '@osf/shared/helpers/types.helper'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse, ListResponse } from '@osf/shared/models/common/json-api/responses.model'; -export interface MeetingGetResponseJsonApi { - id: string; - type: 'meetings'; - attributes: { - name: string; - location: string; - start_date: Date; - end_date: Date; - submissions_count: number; - }; +export type MeetingsListResponseJsonApi = ListResponse; +export type MeetingSubmissionsListResponseJsonApi = ListResponse; +export type MeetingResponseJsonApi = ItemResponse; + +export type MeetingDataJsonApi = JsonApiResource<'meetings', MeetingAttributesJsonApi>; + +export interface MeetingSubmissionDataJsonApi extends JsonApiResource< + 'meeting-submissions', + MeetingSubmissionAttributesJsonApi +> { + links: MeetingSubmissionLinksJsonApi; +} + +interface MeetingAttributesJsonApi { + end_date: Date; + location: string; + name: string; + start_date: Date; + submissions_count: number; +} + +interface MeetingSubmissionAttributesJsonApi { + author_name: string; + date_created: Date; + download_count: NumberOrNull; + meeting_category: string; + title: string; } -export interface MeetingSubmissionGetResponseJsonApi { - id: string; - type: 'meeting-submissions'; - attributes: { - title: string; - date_created: Date; - author_name: string; - download_count: NumberOrNull; - meeting_category: string; - }; - links: { - download: StringOrNull; - }; +interface MeetingSubmissionLinksJsonApi { + download: StringOrNull; } diff --git a/src/app/features/meetings/services/meetings.service.ts b/src/app/features/meetings/services/meetings.service.ts index d3dc25201..d0f95e029 100644 --- a/src/app/features/meetings/services/meetings.service.ts +++ b/src/app/features/meetings/services/meetings.service.ts @@ -4,15 +4,15 @@ import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { searchPreferencesToJsonApiQueryParams } from '@osf/shared/helpers/search-pref-to-json-api-query-params.helper'; -import { JsonApiResponse, ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; import { SearchFilters } from '@osf/shared/models/search-filters.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; import { meetingSortFieldMap, meetingSubmissionSortFieldMap } from '../constants'; import { MeetingsMapper } from '../mappers'; import { - MeetingGetResponseJsonApi, - MeetingSubmissionGetResponseJsonApi, + MeetingResponseJsonApi, + MeetingsListResponseJsonApi, + MeetingSubmissionsListResponseJsonApi, MeetingSubmissionsWithPaging, MeetingsWithPaging, } from '../models'; @@ -38,7 +38,7 @@ export class MeetingsService { ); return this.jsonApiService - .get>(this.apiUrl, params) + .get(this.apiUrl, params) .pipe(map((response) => MeetingsMapper.fromMeetingsGetResponse(response))); } @@ -57,13 +57,13 @@ export class MeetingsService { ); return this.jsonApiService - .get>(`${this.apiUrl}${meetingId}/submissions/`, params) + .get(`${this.apiUrl}${meetingId}/submissions/`, params) .pipe(map((response) => MeetingsMapper.fromMeetingSubmissionGetResponse(response))); } getMeetingById(meetingId: string) { return this.jsonApiService - .get>(this.apiUrl + meetingId) + .get(this.apiUrl + meetingId) .pipe(map((response) => MeetingsMapper.fromMeetingGetResponse(response.data))); } } diff --git a/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.html b/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.html index 9fbe071e8..634051a81 100644 --- a/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.html +++ b/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.html @@ -2,7 +2,7 @@
@if (readonly()) {
- @if (existingRecord()?.attributes?.is_published) { + @if (existingRecord()?.isPublished) {

{{ 'project.metadata.addMetadata.publishedText' | translate }}

} @else {

{{ 'project.metadata.addMetadata.notPublishedText' | translate }}

@@ -58,14 +58,14 @@

{{ 'project.metadata.addMetadata.notPublishedTe } @else { { let component: CedarTemplateFormComponent; let fixture: ComponentFixture; - const mockTemplate = CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK; + const mockTemplate = MOCK_CEDAR_METADATA_TEMPLATE; + const mockRecord = MOCK_CEDAR_METADATA_RECORD; beforeEach(() => { TestBed.configureTestingModule({ @@ -43,10 +44,10 @@ describe('CedarTemplateFormComponent', () => { }); it('should set existingRecord input', () => { - fixture.componentRef.setInput('existingRecord', mockTemplate); + fixture.componentRef.setInput('existingRecord', mockRecord); fixture.detectChanges(); - expect(component.existingRecord()).toEqual(mockTemplate); + expect(component.existingRecord()).toEqual(mockRecord); }); it('should set readonly input', () => { diff --git a/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.ts b/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.ts index 76bbf33ed..3072ae81d 100644 --- a/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.ts +++ b/src/app/features/metadata/components/cedar-template-form/cedar-template-form.component.ts @@ -30,8 +30,8 @@ import { CEDAR_CONFIG, CEDAR_VIEWER_CONFIG } from '../../constants'; import { CedarMetadataHelper } from '../../helpers'; import { CedarEditorElement, - CedarMetadataDataTemplateJsonApi, - CedarMetadataRecordData, + CedarMetadataRecordModel, + CedarMetadataTemplateModel, CedarRecordDataBinding, } from '../../models'; @@ -49,8 +49,8 @@ export class CedarTemplateFormComponent { changeTemplate = output(); toggleEditMode = output(); - template = input.required(); - existingRecord = input(null); + template = input.required(); + existingRecord = input(null); readonly = input(false); showEditButton = input(false); @@ -91,14 +91,14 @@ export class CedarTemplateFormComponent { constructor() { effect(() => { const tpl = this.template(); - if (tpl?.attributes?.template) { + if (tpl?.template) { this.initializeCedar(); } }); effect(() => { const record = this.existingRecord(); - this.schemaName.set(record?.embeds?.template.data.attributes.schema_name || ''); + this.schemaName.set(record?.schemaName || ''); if (record) { this.initializeCedar(); } @@ -106,7 +106,7 @@ export class CedarTemplateFormComponent { } private initializeCedar(): void { - const metadata = this.existingRecord()?.attributes?.metadata; + const metadata = this.existingRecord()?.metadata; const editor = this.cedarEditor()?.nativeElement; const viewer = this.cedarViewer()?.nativeElement; @@ -126,9 +126,9 @@ export class CedarTemplateFormComponent { } private initializeFormData(): void { - const template = this.template()?.attributes?.template; + const template = this.template()?.template; if (!template) return; - const metadata = this.existingRecord()?.attributes?.metadata; + const metadata = this.existingRecord()?.metadata; if (this.existingRecord()) { const structuredMetadata = CedarMetadataHelper.buildStructuredMetadata(metadata); this.formData.set(structuredMetadata); diff --git a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html index 67e98e8f0..8332fca90 100644 --- a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html +++ b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html @@ -26,7 +26,7 @@
diff --git a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts index 7f0606a4a..8ecd342d8 100644 --- a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts +++ b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { CollectionSubmissionReviewState } from '@osf/shared/enums/collection-submission-review-state.enum'; -import { CollectionSubmission } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmission } from '@osf/shared/models/collections/collection-submissions.model'; import { MOCK_CEDAR_RECORD, diff --git a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts index d1d5d0967..7ddc37f58 100644 --- a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts +++ b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts @@ -13,12 +13,13 @@ import { } from '@angular/core'; import { RouterLink } from '@angular/router'; -import { CEDAR_VIEWER_CONFIG } from '@osf/features/metadata/constants'; -import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models'; import { CollectionSubmissionReviewState } from '@osf/shared/enums/collection-submission-review-state.enum'; -import { CollectionSubmission } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmission } from '@osf/shared/models/collections/collection-submissions.model'; import { CollectionStatusSeverityPipe } from '@osf/shared/pipes/collection-status-severity.pipe'; +import { CEDAR_VIEWER_CONFIG } from '../../constants'; +import { CedarMetadataRecordModel, CedarMetadataTemplateModel } from '../../models'; + @Component({ selector: 'osf-metadata-collection-item', imports: [TranslatePipe, Tag, Button, RouterLink, CollectionStatusSeverityPipe], @@ -32,8 +33,8 @@ export class MetadataCollectionItemComponent { readonly CollectionSubmissionReviewState = CollectionSubmissionReviewState; submission = input.required(); - cedarRecord = input(null); - cedarTemplate = input(null); + cedarRecord = input(null); + cedarTemplate = input(null); cedarViewerConfig = CEDAR_VIEWER_CONFIG; @@ -48,12 +49,12 @@ export class MetadataCollectionItemComponent { showCedarViewer = computed( () => !!this.cedarRecord() && - !!this.cedarTemplate()?.attributes?.template && + !!this.cedarTemplate()?.template && this.submission().reviewsState !== CollectionSubmissionReviewState.Removed ); cedarMetadata = computed(() => { const record = this.cedarRecord(); - return record?.attributes?.metadata ? (record.attributes.metadata as Record) : {}; + return record?.metadata ? (record.metadata as Record) : {}; }); } diff --git a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts index eb46f0dda..8102cef73 100644 --- a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts +++ b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts @@ -5,9 +5,9 @@ import { Skeleton } from 'primeng/skeleton'; import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core'; -import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models'; -import { CollectionSubmission } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmission } from '@osf/shared/models/collections/collection-submissions.model'; +import { CedarMetadataRecordModel, CedarMetadataTemplateModel } from '../../models'; import { MetadataCollectionItemComponent } from '../metadata-collection-item/metadata-collection-item.component'; @Component({ @@ -20,14 +20,14 @@ import { MetadataCollectionItemComponent } from '../metadata-collection-item/met export class MetadataCollectionsComponent { projectSubmissions = input(null); isProjectSubmissionsLoading = input(false); - cedarRecords = input(null); - cedarTemplates = input(null); + cedarRecords = input(null); + cedarTemplates = input(null); cedarRecordByTemplateId = computed(() => { const records = this.cedarRecords(); return new Map( records?.flatMap((record) => { - const templateId = record.relationships?.template?.data?.id; + const templateId = record.templateId; return templateId ? [[templateId, record] as const] : []; }) ?? [] ); diff --git a/src/app/features/metadata/mappers/cedar-metadata.mapper.ts b/src/app/features/metadata/mappers/cedar-metadata.mapper.ts new file mode 100644 index 000000000..62541da8b --- /dev/null +++ b/src/app/features/metadata/mappers/cedar-metadata.mapper.ts @@ -0,0 +1,42 @@ +import { CedarMetadataRecordModel } from '../models/cedar-metadata-record.model'; +import { CedarMetadataRecordDataJsonApi } from '../models/cedar-metadata-record-json-api.model'; +import { CedarMetadataTemplateModel, PaginatedCedarTemplatesModel } from '../models/cedar-metadata-template.model'; +import { + CedarMetadataDataTemplateJsonApi, + CedarMetadataTemplateJsonApi, +} from '../models/cedar-metadata-template-json-api.model'; + +export class CedarMetadataMapper { + static fromTemplate(data: CedarMetadataDataTemplateJsonApi): CedarMetadataTemplateModel { + return { + id: data.id, + schemaName: data.attributes.schema_name, + isForCollections: data.attributes.is_for_collections, + active: data.attributes.active, + cedarId: data.attributes.cedar_id, + template: data.attributes.template, + }; + } + + static fromTemplatesResponse(response: CedarMetadataTemplateJsonApi): PaginatedCedarTemplatesModel { + return { + data: response.data.map((item) => this.fromTemplate(item)), + links: { + first: response.links?.first, + next: response.links?.next, + last: response.links?.last, + }, + }; + } + + static fromRecord(data: CedarMetadataRecordDataJsonApi): CedarMetadataRecordModel { + return { + id: data.id ?? '', + metadata: data.attributes.metadata, + isPublished: data.attributes.is_published, + templateId: data.relationships.template.data.id, + targetId: data.relationships.target.data.id, + schemaName: data.embeds?.template?.data?.attributes?.schema_name ?? '', + }; + } +} diff --git a/src/app/features/metadata/mappers/cedar-records.mapper.ts b/src/app/features/metadata/mappers/cedar-records.mapper.ts index afe093d10..164b4e7dd 100644 --- a/src/app/features/metadata/mappers/cedar-records.mapper.ts +++ b/src/app/features/metadata/mappers/cedar-records.mapper.ts @@ -1,11 +1,11 @@ -import { CedarMetadataRecord, CedarRecordDataBinding } from '../models'; +import { CedarMetadataRecordResponseJsonApi, CedarRecordDataBinding } from '../models'; export class CedarRecordsMapper { static toCedarRecordsPayload( data: CedarRecordDataBinding, resourceId: string, resourceType: string - ): CedarMetadataRecord { + ): CedarMetadataRecordResponseJsonApi { return { data: { type: 'cedar_metadata_records', diff --git a/src/app/features/metadata/mappers/index.ts b/src/app/features/metadata/mappers/index.ts index 5c0905874..7e6b2ee61 100644 --- a/src/app/features/metadata/mappers/index.ts +++ b/src/app/features/metadata/mappers/index.ts @@ -1,3 +1,4 @@ +export * from './cedar-metadata.mapper'; export * from './cedar-records.mapper'; export * from './metadata.mapper'; export * from './ror.mapper'; diff --git a/src/app/features/metadata/mappers/metadata.mapper.ts b/src/app/features/metadata/mappers/metadata.mapper.ts index eb6044cb3..8aeeb95d0 100644 --- a/src/app/features/metadata/mappers/metadata.mapper.ts +++ b/src/app/features/metadata/mappers/metadata.mapper.ts @@ -2,10 +2,10 @@ import { IdentifiersMapper } from '@osf/shared/mappers/identifiers.mapper'; import { LicensesMapper } from '@osf/shared/mappers/licenses.mapper'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; -import { CustomItemMetadataRecord, CustomMetadataJsonApi, MetadataJsonApi, MetadataModel } from '../models'; +import { CustomItemMetadataRecord, CustomMetadataDataJsonApi, MetadataDataJsonApi, MetadataModel } from '../models'; export class MetadataMapper { - static fromMetadataApiResponse(response: MetadataJsonApi): MetadataModel { + static fromMetadataApiResponse(response: MetadataDataJsonApi): MetadataModel { return { id: response.id, title: replaceBadEncodedChars(response.attributes.title), @@ -14,7 +14,9 @@ export class MetadataMapper { dateCreated: response.attributes.date_created, dateModified: response.attributes.date_modified, publicationDoi: response.attributes.article_doi, - license: LicensesMapper.fromLicenseDataJsonApi(response.embeds?.license?.data), + license: response.embeds?.license?.data + ? LicensesMapper.fromLicenseDataJsonApi(response.embeds?.license?.data) + : null, nodeLicense: response.attributes.node_license ? { copyrightHolders: response.attributes.node_license.copyright_holders || [], @@ -22,14 +24,14 @@ export class MetadataMapper { } : undefined, identifiers: IdentifiersMapper.fromJsonApi(response.embeds?.identifiers), - provider: response.embeds?.provider?.data.id, + provider: response.relationships?.provider?.data?.id, public: response.attributes.public, currentUserPermissions: response.attributes.current_user_permissions, registrationSupplement: response.attributes.registration_supplement, }; } - static fromCustomMetadataApiResponse(response: CustomMetadataJsonApi): Partial { + static fromCustomMetadataApiResponse(response: CustomMetadataDataJsonApi): Partial { return { language: response.attributes.language, resourceTypeGeneral: response.attributes.resource_type_general, diff --git a/src/app/features/metadata/metadata.component.ts b/src/app/features/metadata/metadata.component.ts index f82c3fec4..f5f77f5db 100644 --- a/src/app/features/metadata/metadata.component.ts +++ b/src/app/features/metadata/metadata.component.ts @@ -74,8 +74,8 @@ import { PublicationDoiDialogComponent } from './dialogs/publication-doi-dialog/ import { ResourceInformationDialogComponent } from './dialogs/resource-information-dialog/resource-information-dialog.component'; import { ResourceInfoTooltipComponent } from './dialogs/resource-tooltip-info/resource-tooltip-info.component'; import { - CedarMetadataDataTemplateJsonApi, - CedarMetadataRecordData, + CedarMetadataRecordModel, + CedarMetadataTemplateModel, CedarRecordDataBinding, DialogValueModel, } from './models'; @@ -133,8 +133,8 @@ export class MetadataComponent implements OnInit, OnDestroy { tabs = signal([]); selectedTab = signal('osf'); - selectedCedarRecord = signal(null); - selectedCedarTemplate = signal(null); + selectedCedarRecord = signal(null); + selectedCedarTemplate = signal(null); cedarFormReadonly = signal(true); resourceType = signal(this.activeRoute.parent?.snapshot.data['resourceType'] || ResourceType.Project); @@ -219,7 +219,7 @@ export class MetadataComponent implements OnInit, OnDestroy { const cedarTabs = records?.map((record) => ({ id: record.id || '', - label: record.embeds?.template?.data?.attributes?.schema_name || `Record ${record.id}`, + label: record.schemaName || `Record ${record.id}`, type: MetadataResourceEnum.CEDAR, })) || []; @@ -232,7 +232,7 @@ export class MetadataComponent implements OnInit, OnDestroy { const selectedRecord = this.selectedCedarRecord(); if (selectedRecord && templates?.data && !this.selectedCedarTemplate()) { - const templateId = selectedRecord.relationships?.template?.data?.id; + const templateId = selectedRecord.templateId; if (templateId) { const template = templates.data.find((t) => t.id === templateId); if (template) { @@ -574,7 +574,7 @@ export class MetadataComponent implements OnInit, OnDestroy { this.selectedCedarRecord.set(record); this.cedarFormReadonly.set(true); - const templateId = record.relationships?.template?.data?.id; + const templateId = record.templateId; if (templateId && templates?.data) { const template = templates.data.find((t) => t.id === templateId); diff --git a/src/app/features/metadata/models/cedar-metadata-attributes.model.ts b/src/app/features/metadata/models/cedar-metadata-attributes.model.ts new file mode 100644 index 000000000..6d2398d0b --- /dev/null +++ b/src/app/features/metadata/models/cedar-metadata-attributes.model.ts @@ -0,0 +1,4 @@ +export interface CedarMetadataAttributes { + '@context': Record; + [field: string]: unknown; +} diff --git a/src/app/features/metadata/models/cedar-metadata-record-json-api.model.ts b/src/app/features/metadata/models/cedar-metadata-record-json-api.model.ts new file mode 100644 index 000000000..785f0fc26 --- /dev/null +++ b/src/app/features/metadata/models/cedar-metadata-record-json-api.model.ts @@ -0,0 +1,27 @@ +import { Embed } from '@osf/shared/models/common/json-api/embeds.model'; +import { ToOneRelData } from '@osf/shared/models/common/json-api/relationships.model'; +import { DataResponse, ListResponse } from '@osf/shared/models/common/json-api/responses.model'; + +import { CedarMetadataAttributes } from './cedar-metadata-attributes.model'; +import { CedarMetadataDataTemplateJsonApi } from './cedar-metadata-template-json-api.model'; + +export type CedarMetadataRecordJsonApi = ListResponse; +export type CedarMetadataRecordResponseJsonApi = DataResponse; + +export interface CedarMetadataRecordDataJsonApi { + id?: string; + type?: string; + attributes: CedarMetadataRecordAttributesJsonApi; + embeds?: { + template: Embed; + }; + relationships: { + template: ToOneRelData; + target: ToOneRelData; + }; +} + +interface CedarMetadataRecordAttributesJsonApi { + metadata: CedarMetadataAttributes; + is_published: boolean; +} diff --git a/src/app/features/metadata/models/cedar-metadata-record.model.ts b/src/app/features/metadata/models/cedar-metadata-record.model.ts new file mode 100644 index 000000000..c3cf894de --- /dev/null +++ b/src/app/features/metadata/models/cedar-metadata-record.model.ts @@ -0,0 +1,16 @@ +import { CedarMetadataAttributes } from './cedar-metadata-attributes.model'; + +export interface CedarMetadataRecordModel { + id: string; + metadata: CedarMetadataAttributes; + isPublished: boolean; + templateId: string; + targetId: string; + schemaName: string; +} + +export interface CedarRecordDataBinding { + id: string; + data: CedarMetadataAttributes; + isPublished: boolean; +} diff --git a/src/app/features/metadata/models/cedar-metadata-template-json-api.model.ts b/src/app/features/metadata/models/cedar-metadata-template-json-api.model.ts new file mode 100644 index 000000000..b14b5f5b6 --- /dev/null +++ b/src/app/features/metadata/models/cedar-metadata-template-json-api.model.ts @@ -0,0 +1,19 @@ +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; + +import { CedarTemplate } from './cedar-template.model'; + +export type CedarMetadataTemplateJsonApi = ListResponse; + +export type CedarMetadataDataTemplateJsonApi = JsonApiResource< + 'cedar-metadata-templates', + CedarMetadataTemplateAttributesJsonApi +>; + +interface CedarMetadataTemplateAttributesJsonApi { + active: boolean; + cedar_id: string; + schema_name: string; + template: CedarTemplate; + is_for_collections: boolean; +} diff --git a/src/app/features/metadata/models/cedar-metadata-template.model.ts b/src/app/features/metadata/models/cedar-metadata-template.model.ts index 7b904d7ea..f385f479e 100644 --- a/src/app/features/metadata/models/cedar-metadata-template.model.ts +++ b/src/app/features/metadata/models/cedar-metadata-template.model.ts @@ -1,254 +1,17 @@ -import { MetaJsonApi, PaginationLinksJsonApi } from '@osf/shared/models/common/json-api.model'; +import { PaginationLinks } from '@osf/shared/models/common/json-api/links.model'; -export interface CedarMetadataDataTemplateJsonApi { - id: string; - type: 'cedar-metadata-templates'; - attributes: { - schema_name: string; - cedar_id: string; - template: CedarTemplate; - is_for_collections: boolean; - }; -} - -export const CEDAR_TEMPLATE_FIELD_TYPE = 'https://schema.metadatacenter.org/core/TemplateField'; -export const CEDAR_PROPERTIES_BASE_IRI = 'https://schema.metadatacenter.org/properties/'; - -export interface CedarTemplateField { - '@type': string; - _valueConstraints?: { - literals?: { label: string }[]; - multipleChoice?: boolean; - requiredValue?: boolean; - }; -} - -export interface CedarTemplateContextSchema { - properties: Record; -} - -export interface CedarTemplate { - '@id': string; - '@type': string; - type: string; - title: string; - description: string; - $schema: string; - '@context': CedarTemplateContext; - required: string[]; - properties: Record; - _ui: { - order: string[]; - propertyLabels: Record; - propertyDescriptions: Record; - }; -} - -export interface CedarTemplateContext { - pav: string; - xsd: string; - bibo: string; - oslc: string; - schema: string; - 'schema:name': { - '@type': string; - }; - 'pav:createdBy': { - '@type': string; - }; - 'pav:createdOn': { - '@type': string; - }; - 'oslc:modifiedBy': { - '@type': string; - }; - 'pav:lastUpdatedOn': { - '@type': string; - }; - 'schema:description': { - '@type': string; - }; -} - -export interface CedarMetadataTemplate { - id: string; - type: 'cedar-metadata-templates'; - attributes: { - schema_name: string; - cedar_id: string; - template: CedarTemplate; - is_for_collections: boolean; - }; -} - -export interface CedarTemplate { - '@id': string; - '@type': string; - type: string; - title: string; - $schema: string; - '@context': CedarTemplateContext; - required: string[]; - properties: Record; - _ui: { - order: string[]; - propertyLabels: Record; - propertyDescriptions: Record; - }; -} - -export interface CedarTemplateContext { - pav: string; - xsd: string; - bibo: string; - oslc: string; - schema: string; - 'schema:name': { - '@type': string; - }; - 'pav:createdBy': { - '@type': string; - }; - 'pav:createdOn': { - '@type': string; - }; - 'oslc:modifiedBy': { - '@type': string; - }; - 'pav:lastUpdatedOn': { - '@type': string; - }; - 'schema:description': { - '@type': string; - }; -} - -export interface CedarMetadataTemplateJsonApi { - data: CedarMetadataDataTemplateJsonApi[]; - links: PaginationLinksJsonApi; -} - -export interface FieldSchema { - type?: string; - format?: string; - title?: string; - description?: string; - maxLength?: number; - items?: FieldSchema; - properties?: Record; - required?: string[]; - _ui?: { - inputType?: string; - order?: string[]; - propertyLabels?: Record; - propertyDescriptions?: Record; - }; - 'schema:name'?: string; - 'schema:description'?: string; - '@id': string; -} - -export interface CedarFieldItem extends Record { - '@id'?: string; - '@type'?: string; - 'rdfs:label'?: string | null; - '@value'?: string; -} - -export interface CedarMetadataAttributes { - '@context': Record; - Constructs: CedarFieldItem[]; - Assessments: CedarFieldItem[]; - Organization: { - '@id': string; - '@context': { - OrganizationID: string; - OrganizationName: string; - }; - OrganizationID: Record; - OrganizationName: { - '@value': string; - }; - }[]; - 'Project Name': { - '@value': string; - }; - LDbaseWebsite: Record; - 'Project Methods': CedarFieldItem[]; - 'Participant Types': CedarFieldItem[]; - 'Special Populations': CedarFieldItem[]; - 'Developmental Design': Record; - LDbaseProjectEndDate: { - '@type': string; - '@value': string; - }; - 'Educational Curricula': CedarFieldItem[]; - LDbaseInvestigatorORCID: CedarFieldItem[]; - LDbaseProjectStartDates: { - '@type': string; - '@value': string; - }; - 'Educational Environments': Record; - LDbaseProjectDescription: { - '@value': string; - }; - - [key: string]: unknown; +import { CedarTemplate } from './cedar-template.model'; - LDbaseProjectContributors: { - '@value': string; - }[]; -} - -export interface CedarMetadataRecord { - data: CedarMetadataRecordData; -} - -export interface CedarRecordDataBinding { - data: CedarMetadataAttributes; +export interface CedarMetadataTemplateModel { id: string; - isPublished: boolean; -} - -export interface CedarMetadataRecordJsonApi { - data: CedarMetadataRecordData[]; - links: PaginationLinksJsonApi; - meta: MetaJsonApi; -} - -export interface CedarMetadataRecordData { - id?: string; - attributes: CedarMetadataRecordAttributes; - embeds?: { - template: { - data: { - attributes: { - active: boolean; - cedar_id: string; - schema_name: string; - }; - id: string; - }; - }; - }; - relationships: { - template: { - data: { - type: string; - id: string; - }; - }; - target: { - data: { - type: string; - id: string; - }; - }; - }; - type?: string; + schemaName: string; + isForCollections: boolean; + active: boolean; + cedarId: string; + template: CedarTemplate; } -export interface CedarMetadataRecordAttributes { - metadata: CedarMetadataAttributes; - is_published: boolean; +export interface PaginatedCedarTemplatesModel { + data: CedarMetadataTemplateModel[]; + links: PaginationLinks; } diff --git a/src/app/features/metadata/models/cedar-template.model.ts b/src/app/features/metadata/models/cedar-template.model.ts new file mode 100644 index 000000000..af6ad9619 --- /dev/null +++ b/src/app/features/metadata/models/cedar-template.model.ts @@ -0,0 +1,78 @@ +export const CEDAR_TEMPLATE_FIELD_TYPE = 'https://schema.metadatacenter.org/core/TemplateField'; +export const CEDAR_PROPERTIES_BASE_IRI = 'https://schema.metadatacenter.org/properties/'; + +export interface CedarTemplateField { + '@type': string; + _valueConstraints?: { + literals?: { label: string }[]; + multipleChoice?: boolean; + requiredValue?: boolean; + }; +} + +export interface CedarTemplateContextSchema { + properties: Record; +} + +export interface CedarTemplate { + '@id': string; + '@type': string; + type: string; + title: string; + description: string; + $schema: string; + '@context': CedarTemplateContext; + required: string[]; + properties: Record; + _ui: { + order: string[]; + propertyLabels: Record; + propertyDescriptions: Record; + }; +} + +interface CedarTemplateContext { + pav: string; + xsd: string; + bibo: string; + oslc: string; + schema: string; + 'schema:name': { + '@type': string; + }; + 'pav:createdBy': { + '@type': string; + }; + 'pav:createdOn': { + '@type': string; + }; + 'oslc:modifiedBy': { + '@type': string; + }; + 'pav:lastUpdatedOn': { + '@type': string; + }; + 'schema:description': { + '@type': string; + }; +} + +export interface FieldSchema { + type?: string; + format?: string; + title?: string; + description?: string; + maxLength?: number; + items?: FieldSchema; + properties?: Record; + required?: string[]; + _ui?: { + inputType?: string; + order?: string[]; + propertyLabels?: Record; + propertyDescriptions?: Record; + }; + 'schema:name'?: string; + 'schema:description'?: string; + '@id': string; +} diff --git a/src/app/features/metadata/models/index.ts b/src/app/features/metadata/models/index.ts index 30e978c95..f7cc29849 100644 --- a/src/app/features/metadata/models/index.ts +++ b/src/app/features/metadata/models/index.ts @@ -1,5 +1,10 @@ export * from './cedar-editor-element.model'; +export * from './cedar-metadata-attributes.model'; +export * from './cedar-metadata-record.model'; +export * from './cedar-metadata-record-json-api.model'; export * from './cedar-metadata-template.model'; +export * from './cedar-metadata-template-json-api.model'; +export * from './cedar-template.model'; export * from './dialog-value.model'; export * from './funding-dialog.model'; export * from './metadata.model'; diff --git a/src/app/features/metadata/models/metadata-json-api.model.ts b/src/app/features/metadata/models/metadata-json-api.model.ts index 802777461..ce91803fb 100644 --- a/src/app/features/metadata/models/metadata-json-api.model.ts +++ b/src/app/features/metadata/models/metadata-json-api.model.ts @@ -1,58 +1,59 @@ +import { ToOneRel } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; import { UserPermissions } from '@shared/enums/user-permissions.enum'; -import { ApiData } from '@shared/models/common/json-api.model'; +import { Embed } from '@shared/models/common/json-api/embeds.model'; +import { ItemResponse } from '@shared/models/common/json-api/responses.model'; import { IdentifiersResponseJsonApi } from '@shared/models/identifiers/identifier-json-api.model'; -import { InstitutionsJsonApiResponse } from '@shared/models/institutions/institution-json-api.model'; import { LicenseDataJsonApi, LicenseRecordJsonApi } from '@shared/models/license/licenses-json-api.model'; -export interface MetadataJsonApiResponse { - data: MetadataJsonApi; +export type MetadataResponseJsonApi = ItemResponse; +export type CustomMetadataResponseJsonApi = ItemResponse; + +export interface MetadataDataJsonApi extends JsonApiResource<'metadata', MetadataAttributesJsonApi> { + relationships: MetadataRelationshipsJsonApi; + embeds?: MetadataEmbedsJsonApi; } -export type MetadataJsonApi = ApiData; +export type CustomMetadataDataJsonApi = JsonApiResource< + 'custom-item-metadata-records', + CustomMetadataAttributesJsonApi +>; export interface MetadataAttributesJsonApi { - title: string; - description: string; - tags: string[]; + article_doi?: string; + category?: string; + current_user_permissions: UserPermissions[]; date_created: string; date_modified: string; - article_doi?: string; + description: string; doi?: boolean; - category?: string; node_license?: LicenseRecordJsonApi; public?: boolean; registration_supplement?: string; - current_user_permissions: UserPermissions[]; -} - -interface MetadataEmbedsJsonApi { - affiliated_institutions: InstitutionsJsonApiResponse; - identifiers: IdentifiersResponseJsonApi; - license: { - data: LicenseDataJsonApi; - }; - provider?: { - data: { id: string; type: string; attributes: { name: string } }; - }; -} - -export interface CustomMetadataJsonApiResponse { - data: CustomMetadataJsonApi; + tags: string[]; + title: string; } -export type CustomMetadataJsonApi = ApiData; - -export interface CustomMetadataAttributesJsonApi { +interface CustomMetadataAttributesJsonApi { + funders?: FunderJsonApi[]; language?: string; resource_type_general?: string; - funders?: FunderJsonApi[]; } -export interface FunderJsonApi { - funder_name: string; - funder_identifier: string; - funder_identifier_type: string; +interface FunderJsonApi { award_number: string; - award_uri: string; award_title: string; + award_uri: string; + funder_identifier: string; + funder_identifier_type: string; + funder_name: string; +} + +interface MetadataEmbedsJsonApi { + identifiers: IdentifiersResponseJsonApi; + license: Embed; +} + +interface MetadataRelationshipsJsonApi { + provider: ToOneRel; } diff --git a/src/app/features/metadata/models/ror.model.ts b/src/app/features/metadata/models/ror.model.ts index 5775df7e4..a4ddede3a 100644 --- a/src/app/features/metadata/models/ror.model.ts +++ b/src/app/features/metadata/models/ror.model.ts @@ -1,4 +1,40 @@ -export interface RorAdmin { +export interface RorSearchResponse { + items: RorOrganization[]; + meta: RorMeta; + number_of_results: number; + time_taken: number; +} + +export interface RorFunderOption { + id: string; + name: string; +} + +export interface RorOrganization { + id: string; + admin: RorAdmin; + domains: string[]; + established: number | null; + external_ids: RorExternalId[]; + links: RorLink[]; + locations: RorLocation[]; + names: RorName[]; + relationships: RorRelationship[]; + status: 'active' | 'inactive' | 'withdrawn'; + types: ( + | 'education' + | 'healthcare' + | 'company' + | 'archive' + | 'nonprofit' + | 'government' + | 'facility' + | 'other' + | 'funder' + )[]; +} + +interface RorAdmin { created: { date: string; schema_version: string; @@ -9,18 +45,18 @@ export interface RorAdmin { }; } -export interface RorExternalId { +interface RorExternalId { all: string[]; preferred: string | null; type: 'grid' | 'fundref' | 'isni' | 'wikidata'; } -export interface RorLink { +interface RorLink { type: 'website' | 'wikipedia'; value: string; } -export interface RorGeonamesDetails { +interface RorGeonamesDetails { continent_code: string; continent_name: string; country_code: string; @@ -32,80 +68,32 @@ export interface RorGeonamesDetails { name: string; } -export interface RorLocation { +interface RorLocation { geonames_details: RorGeonamesDetails; geonames_id: number; } -export interface RorName { +interface RorName { lang: string | null; types: ('ror_display' | 'label' | 'alias' | 'acronym')[]; value: string; } -export interface RorRelationship { +interface RorRelationship { type: string; id: string; label: string; } -export interface RorOrganization { - id: string; - admin: RorAdmin; - domains: string[]; - established: number | null; - external_ids: RorExternalId[]; - links: RorLink[]; - locations: RorLocation[]; - names: RorName[]; - relationships: RorRelationship[]; - status: 'active' | 'inactive' | 'withdrawn'; - types: ( - | 'education' - | 'healthcare' - | 'company' - | 'archive' - | 'nonprofit' - | 'government' - | 'facility' - | 'other' - | 'funder' - )[]; -} - -export interface RorMetaCount { +interface RorMetaCount { id: string; title: string; count: number; } -export interface RorMeta { +interface RorMeta { types: RorMetaCount[]; countries: RorMetaCount[]; continents: RorMetaCount[]; statuses: RorMetaCount[]; } - -export interface RorSearchResponse { - items: RorOrganization[]; - meta: RorMeta; - number_of_results: number; - time_taken: number; -} - -export interface RorFunderOption { - id: string; - name: string; -} - -export interface RorDisplayData { - id: string; - displayName: string; - acronym?: string; - type: string; - country: string; - city: string; - established?: number; - website?: string; - status: string; -} diff --git a/src/app/features/metadata/pages/add-metadata/add-metadata.component.html b/src/app/features/metadata/pages/add-metadata/add-metadata.component.html index 21d47d7c1..ffffe2a3c 100644 --- a/src/app/features/metadata/pages/add-metadata/add-metadata.component.html +++ b/src/app/features/metadata/pages/add-metadata/add-metadata.component.html @@ -20,15 +20,16 @@

{{ 'project.metadata.addMetadata.selectTemplate' | translate }}

[class.metadata-item]="isMedium()" >
-

{{ meta.attributes.template.title }}

+

{{ meta.template.title }}

-

{{ meta.attributes.template.description }}

+

{{ meta.template.description }}

@if (hasExistingRecord(meta.id)) { {{ meta.attributes.template.title }}

> } @else { { let activatedRoute: Partial; let toastService: ReturnType; - const mockTemplate = CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK; - const mockRecord = MOCK_CEDAR_METADATA_RECORD_DATA; + const mockTemplate = MOCK_CEDAR_METADATA_TEMPLATE; + const mockRecord = MOCK_CEDAR_METADATA_RECORD; const mockCedarTemplates = { data: [mockTemplate], @@ -81,7 +80,7 @@ describe('AddMetadataComponent', () => { { selector: MetadataSelectors.getCedarTemplatesExcludingCollections, value: mockCedarTemplates }, { selector: MetadataSelectors.getCedarRecords, value: mockCedarRecords }, { selector: MetadataSelectors.getCedarTemplatesLoading, value: false }, - { selector: MetadataSelectors.getCedarRecord, value: { data: mockRecord } }, + { selector: MetadataSelectors.getCedarRecord, value: mockRecord }, ], }), ], diff --git a/src/app/features/metadata/pages/add-metadata/add-metadata.component.ts b/src/app/features/metadata/pages/add-metadata/add-metadata.component.ts index 20b1d67ef..ab9a7818d 100644 --- a/src/app/features/metadata/pages/add-metadata/add-metadata.component.ts +++ b/src/app/features/metadata/pages/add-metadata/add-metadata.component.ts @@ -25,7 +25,7 @@ import { IS_MEDIUM } from '@osf/shared/helpers/breakpoints.tokens'; import { ToastService } from '@osf/shared/services/toast.service'; import { CedarTemplateFormComponent } from '../../components/cedar-template-form/cedar-template-form.component'; -import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData, CedarRecordDataBinding } from '../../models'; +import { CedarMetadataRecordModel, CedarMetadataTemplateModel, CedarRecordDataBinding } from '../../models'; import { CreateCedarMetadataRecord, GetCedarMetadataRecords, @@ -53,8 +53,8 @@ export class AddMetadataComponent implements OnInit { private resourceId = ''; isEditMode = true; - selectedTemplate: CedarMetadataDataTemplateJsonApi | null = null; - existingRecord: CedarMetadataRecordData | null = null; + selectedTemplate: CedarMetadataTemplateModel | null = null; + existingRecord: CedarMetadataRecordModel | null = null; readonly cedarTemplates = select(MetadataSelectors.getCedarTemplatesExcludingCollections); readonly cedarRecords = select(MetadataSelectors.getCedarRecords); @@ -84,7 +84,7 @@ export class AddMetadataComponent implements OnInit { return record.id === recordId; }); if (existingRecord) { - const templateId = existingRecord.relationships.template.data.id; + const templateId = existingRecord.templateId; const matchingTemplate = cedarTemplatesData.find((template) => template.id === templateId); if (matchingTemplate) { @@ -111,7 +111,7 @@ export class AddMetadataComponent implements OnInit { this.actions.getCedarTemplates(); } - onSelect(template: CedarMetadataDataTemplateJsonApi): void { + onSelect(template: CedarMetadataTemplateModel): void { if (this.hasExistingRecord(template.id)) { return; } @@ -157,7 +157,7 @@ export class AddMetadataComponent implements OnInit { const records = this.cedarRecords(); if (!records) return false; - return records.some((record) => record.relationships.template.data.id === templateId); + return records.some((record) => record.templateId === templateId); } createRecordMetadata(data: CedarRecordDataBinding): void { @@ -192,7 +192,7 @@ export class AddMetadataComponent implements OnInit { } private navigateToRecord(resourceId: string, resourceType: ResourceType): void { - const recordId = this.cedarRecord()?.data.id; + const recordId = this.cedarRecord()?.id; if (resourceType === ResourceType.File) { this.router.navigate([resourceId]); } else { diff --git a/src/app/features/metadata/store/metadata.actions.ts b/src/app/features/metadata/store/metadata.actions.ts index cc3301bca..7755da809 100644 --- a/src/app/features/metadata/store/metadata.actions.ts +++ b/src/app/features/metadata/store/metadata.actions.ts @@ -2,7 +2,7 @@ import { ResourceType } from '@osf/shared/enums/resource-type.enum'; import { LicenseOptions } from '@shared/models/license/license.model'; import { - CedarMetadataRecordData, + CedarMetadataRecordModel, CedarRecordDataBinding, CustomItemMetadataRecord, MetadataAttributesJsonApi, @@ -98,5 +98,5 @@ export class UpdateCedarMetadataRecord { export class AddCedarMetadataRecordToState { static readonly type = '[Metadata] Add Cedar Metadata Record To State'; - constructor(public record: CedarMetadataRecordData) {} + constructor(public record: CedarMetadataRecordModel) {} } diff --git a/src/app/features/metadata/store/metadata.model.ts b/src/app/features/metadata/store/metadata.model.ts index a5e05dc5b..b7f614030 100644 --- a/src/app/features/metadata/store/metadata.model.ts +++ b/src/app/features/metadata/store/metadata.model.ts @@ -1,21 +1,19 @@ import { - CedarMetadataRecord, - CedarMetadataRecordData, - CedarMetadataTemplateJsonApi, + CedarMetadataRecordModel, CustomItemMetadataRecord, + MetadataModel, + PaginatedCedarTemplatesModel, + RorFunderOption, } from '@osf/features/metadata/models'; import { AsyncStateModel } from '@osf/shared/models/store/async-state.model'; -import { MetadataModel } from '../models'; -import { RorFunderOption } from '../models/ror.model'; - export interface MetadataStateModel { metadata: AsyncStateModel; customMetadata: AsyncStateModel; fundersList: AsyncStateModel; - cedarTemplates: AsyncStateModel; - cedarRecord: AsyncStateModel; - cedarRecords: AsyncStateModel; + cedarTemplates: AsyncStateModel; + cedarRecord: AsyncStateModel; + cedarRecords: AsyncStateModel; } export const METADATA_STATE_DEFAULTS: MetadataStateModel = { diff --git a/src/app/features/metadata/store/metadata.selectors.ts b/src/app/features/metadata/store/metadata.selectors.ts index ba86d6cf3..d21ce781b 100644 --- a/src/app/features/metadata/store/metadata.selectors.ts +++ b/src/app/features/metadata/store/metadata.selectors.ts @@ -52,7 +52,7 @@ export class MetadataSelectors { if (!templates) return null; return { ...templates, - data: templates.data.filter((t) => !t.attributes.is_for_collections), + data: templates.data.filter((t) => !t.isForCollections), }; } diff --git a/src/app/features/metadata/store/metadata.state.ts b/src/app/features/metadata/store/metadata.state.ts index 88ac11b71..d0079627c 100644 --- a/src/app/features/metadata/store/metadata.state.ts +++ b/src/app/features/metadata/store/metadata.state.ts @@ -7,7 +7,7 @@ import { inject, Injectable } from '@angular/core'; import { handleSectionError } from '@osf/shared/helpers/state-error.handler'; import { MetadataService } from '@osf/shared/services/metadata.service'; -import { CedarMetadataRecord, CedarMetadataRecordJsonApi, MetadataModel } from '../models'; +import { CedarMetadataRecordModel, MetadataModel } from '../models'; import { AddCedarMetadataRecordToState, @@ -179,10 +179,10 @@ export class MetadataState { }, }); return this.metadataService.getMetadataCedarRecords(action.resourceId, action.resourceType, action.url).pipe( - tap((response: CedarMetadataRecordJsonApi) => { + tap((records: CedarMetadataRecordModel[]) => { ctx.patchState({ cedarRecords: { - data: response.data, + data: records, error: null, isLoading: false, }, @@ -194,15 +194,15 @@ export class MetadataState { @Action(CreateCedarMetadataRecord) createCedarMetadataRecord(ctx: StateContext, action: CreateCedarMetadataRecord) { return this.metadataService.createMetadataCedarRecord(action.record, action.resourceId, action.resourceType).pipe( - tap((response: CedarMetadataRecord) => { + tap((record: CedarMetadataRecordModel) => { ctx.patchState({ cedarRecord: { - data: response, + data: record, error: null, isLoading: false, }, }); - ctx.dispatch(new AddCedarMetadataRecordToState(response.data)); + ctx.dispatch(new AddCedarMetadataRecordToState(record)); }) ); } @@ -212,10 +212,10 @@ export class MetadataState { return this.metadataService .updateMetadataCedarRecord(action.record, action.recordId, action.resourceId, action.resourceType) .pipe( - tap((response: CedarMetadataRecord) => { + tap((updatedRecord: CedarMetadataRecordModel) => { const state = ctx.getState(); const updatedRecords = state.cedarRecords.data.map((record) => - record.id === action.recordId ? response.data : record + record.id === action.recordId ? updatedRecord : record ); ctx.patchState({ cedarRecords: { diff --git a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts index 9d6f23010..1c9574854 100644 --- a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts +++ b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts @@ -4,7 +4,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { IconComponent } from '@osf/shared/components/icon/icon.component'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; import { CollectionsSelectors } from '@osf/shared/stores/collections'; import { DateAgoPipe } from '@shared/pipes/date-ago.pipe'; @@ -24,7 +23,7 @@ describe('CollectionSubmissionItemComponent', () => { let mockRouter: ReturnType; let mockActivatedRoute: ReturnType; - const mockSubmission: CollectionSubmissionWithGuid = MOCK_COLLECTION_SUBMISSION_WITH_GUID; + const mockSubmission = MOCK_COLLECTION_SUBMISSION_WITH_GUID; const mockCollectionProvider = { id: 'provider-123', diff --git a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts index 013686142..6d57c01a2 100644 --- a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts +++ b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts @@ -11,7 +11,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component'; import { IconComponent } from '@osf/shared/components/icon/icon.component'; import { TruncatedTextComponent } from '@osf/shared/components/truncated-text/truncated-text.component'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collection-submissions.model'; import { DateAgoPipe } from '@osf/shared/pipes/date-ago.pipe'; import { CollectionsSelectors } from '@osf/shared/stores/collections'; diff --git a/src/app/features/moderation/components/collection-submissions-list/collection-submissions-list.component.ts b/src/app/features/moderation/components/collection-submissions-list/collection-submissions-list.component.ts index b98c947df..4d45defc7 100644 --- a/src/app/features/moderation/components/collection-submissions-list/collection-submissions-list.component.ts +++ b/src/app/features/moderation/components/collection-submissions-list/collection-submissions-list.component.ts @@ -8,7 +8,7 @@ import { GetCollectionSubmissionContributors, LoadMoreCollectionSubmissionContributors, } from '@osf/features/moderation/store/collections-moderation'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collection-submissions.model'; import { CollectionsModerationSelectors } from '../../store/collections-moderation'; import { CollectionSubmissionItemComponent } from '../collection-submission-item/collection-submission-item.component'; diff --git a/src/app/features/moderation/mappers/moderation.mapper.ts b/src/app/features/moderation/mappers/moderation.mapper.ts index 18af21c2e..160ae8844 100644 --- a/src/app/features/moderation/mappers/moderation.mapper.ts +++ b/src/app/features/moderation/mappers/moderation.mapper.ts @@ -1,7 +1,3 @@ -import { ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; -import { PaginatedData } from '@osf/shared/models/paginated-data.model'; -import { UserDataJsonApi } from '@osf/shared/models/user/user-json-api.model'; - import { AddModeratorType, ModeratorPermission } from '../enums'; import { ModeratorAddModel, ModeratorAddRequestModel, ModeratorDataJsonApi, ModeratorModel } from '../models'; @@ -25,23 +21,6 @@ export class ModerationMapper { }; } - static fromUsersWithPaginationGetResponse( - response: ResponseJsonApi - ): PaginatedData { - return { - data: response.data.map( - (user) => - ({ - id: user.id, - fullName: user.attributes.full_name, - permission: ModeratorPermission.Moderator, - }) as ModeratorAddModel - ), - totalCount: response.meta.total, - pageSize: response.meta.per_page, - }; - } - static toModeratorAddRequest(model: ModeratorAddModel, type = AddModeratorType.Search): ModeratorAddRequestModel { if (type === AddModeratorType.Search) { return { diff --git a/src/app/features/moderation/mappers/preprint-moderation.mapper.ts b/src/app/features/moderation/mappers/preprint-moderation.mapper.ts index 621d929c1..455b11257 100644 --- a/src/app/features/moderation/mappers/preprint-moderation.mapper.ts +++ b/src/app/features/moderation/mappers/preprint-moderation.mapper.ts @@ -1,11 +1,12 @@ +import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants/default-table-params.constants'; import { UserMapper } from '@osf/shared/mappers/user'; -import { ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; import { PaginatedData } from '@osf/shared/models/paginated-data.model'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; import { PreprintProviderModerationInfo, PreprintRelatedCountJsonApi, + PreprintReviewActionListResponseJsonApi, PreprintSubmissionResponseJsonApi, PreprintSubmissionWithdrawalResponseJsonApi, PreprintWithdrawalPaginatedData, @@ -39,12 +40,12 @@ export class PreprintModerationMapper { } static fromResponseWithPagination( - response: ResponseJsonApi + response: PreprintReviewActionListResponseJsonApi ): PaginatedData { return { data: response.data.map((x) => this.fromResponse(x)), totalCount: response.meta.total, - pageSize: response.meta.per_page, + pageSize: response.meta.per_page ?? DEFAULT_TABLE_PARAMS.rows, }; } @@ -73,7 +74,7 @@ export class PreprintModerationMapper { totalContributors: 0, })), totalCount: response.meta.total, - pageSize: response.meta.per_page, + pageSize: response.meta.per_page ?? DEFAULT_TABLE_PARAMS.rows, pendingCount: response.meta?.reviews_state_counts?.pending || 0, acceptedCount: response.meta?.reviews_state_counts?.accepted || 0, rejectedCount: response.meta?.reviews_state_counts?.rejected || 0, @@ -87,14 +88,14 @@ export class PreprintModerationMapper { return { data: response.data.map((x) => ({ id: x.id, - title: replaceBadEncodedChars(x.embeds.target.data.attributes.title), - preprintId: x.embeds.target.data.id, + title: replaceBadEncodedChars(x.embeds.target?.data?.attributes?.title), + preprintId: x.embeds.target?.data?.id, actions: [], contributors: [], totalContributors: 0, })), totalCount: response.meta.total, - pageSize: response.meta.per_page, + pageSize: response.meta.per_page ?? DEFAULT_TABLE_PARAMS.rows, pendingCount: response.meta.requests_state_counts.pending, acceptedCount: response.meta.requests_state_counts.accepted, rejectedCount: response.meta.requests_state_counts.rejected, diff --git a/src/app/features/moderation/mappers/registry-moderation.mapper.ts b/src/app/features/moderation/mappers/registry-moderation.mapper.ts index 70ab5fdb4..bab234290 100644 --- a/src/app/features/moderation/mappers/registry-moderation.mapper.ts +++ b/src/app/features/moderation/mappers/registry-moderation.mapper.ts @@ -1,3 +1,4 @@ +import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants/default-table-params.constants'; import { UserMapper } from '@osf/shared/mappers/user'; import { PaginatedData } from '@osf/shared/models/paginated-data.model'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; @@ -7,7 +8,7 @@ import { RegistryModeration, RegistryResponseJsonApi, ReviewAction, - ReviewActionsDataJsonApi, + ReviewActionDataJsonApi, } from '../models'; export class RegistryModerationMapper { @@ -29,11 +30,11 @@ export class RegistryModerationMapper { return { data: response.data.map((x) => this.fromResponse(x)), totalCount: response.meta.total, - pageSize: response.meta.per_page, + pageSize: response.meta.per_page ?? DEFAULT_TABLE_PARAMS.rows, }; } - static fromActionResponse(response: ReviewActionsDataJsonApi): ReviewAction { + static fromActionResponse(response: ReviewActionDataJsonApi): ReviewAction { const creator = UserMapper.getUserInfo(response.embeds?.creator); return { diff --git a/src/app/features/moderation/models/collection-submission-review-action-json-api.model.ts b/src/app/features/moderation/models/collection-submission-review-action-json-api.model.ts index cca102865..9374bcf29 100644 --- a/src/app/features/moderation/models/collection-submission-review-action-json-api.model.ts +++ b/src/app/features/moderation/models/collection-submission-review-action-json-api.model.ts @@ -1,25 +1,32 @@ +import { ToOneRelData } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export interface CollectionSubmissionReviewActionJsonApi { - id: string; - type: 'collection-submission-actions'; - attributes: { - trigger: string; - comment: string; - from_state: string; - to_state: string; - date_created: string; - date_modified: string; - }; - embeds: { - creator: UserDataErrorResponseJsonApi; - }; - relationships: { - target: { - data: { - id: string; - type: 'collection-submission'; - }; - }; - }; +export type CollectionSubmissionReviewActionsListResponseJsonApi = + ListResponse; + +export interface CollectionSubmissionReviewActionJsonApi extends JsonApiResource< + 'collection-submission-actions', + CollectionSubmissionReviewActionAttributesJsonApi +> { + embeds: CollectionSubmissionReviewActionEmbedsJsonApi; + relationships: CollectionSubmissionReviewActionRelationshipsJsonApi; +} + +interface CollectionSubmissionReviewActionAttributesJsonApi { + comment: string; + date_created: string; + date_modified: string; + from_state: string; + to_state: string; + trigger: string; +} + +interface CollectionSubmissionReviewActionEmbedsJsonApi { + creator: UserDataErrorResponseJsonApi; +} + +interface CollectionSubmissionReviewActionRelationshipsJsonApi { + target: ToOneRelData<'collection-submission'>; } diff --git a/src/app/features/moderation/models/moderator-json-api.model.ts b/src/app/features/moderation/models/moderator-json-api.model.ts index 24449f115..fe2637360 100644 --- a/src/app/features/moderation/models/moderator-json-api.model.ts +++ b/src/app/features/moderation/models/moderator-json-api.model.ts @@ -1,31 +1,32 @@ -import { ApiData, MetaJsonApi, PaginationLinksJsonApi } from '@osf/shared/models/common/json-api.model'; +import { Embed } from '@osf/shared/models/common/json-api/embeds.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse, ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { UserDataJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export interface ModeratorResponseJsonApi { - data: ModeratorDataJsonApi[]; - meta: MetaJsonApi; - links: PaginationLinksJsonApi; +export type ModeratorResponseJsonApi = ListResponse; +export type ModeratorItemResponseJsonApi = ItemResponse; + +export interface ModeratorDataJsonApi extends JsonApiResource<'moderators', ModeratorAttributesJsonApi> { + embeds: ModeratorEmbedsJsonApi; +} + +export interface ModeratorAddRequestModel { + attributes: ModeratorAddAttributesJsonApi; + type: 'moderators'; } -export type ModeratorDataJsonApi = ApiData; +interface ModeratorAddAttributesJsonApi { + email?: string; + full_name?: string; + id?: string; + permission_group: string; +} interface ModeratorAttributesJsonApi { full_name: string; - permission_group: 'moderator' | 'admin'; + permission_group: 'admin' | 'moderator'; } interface ModeratorEmbedsJsonApi { - user: { - data: UserDataJsonApi; - }; -} - -export interface ModeratorAddRequestModel { - type: 'moderators'; - attributes: { - id?: string; - permission_group: string; - full_name?: string; - email?: string; - }; + user: Embed; } diff --git a/src/app/features/moderation/models/preprint-related-count-json-api.model.ts b/src/app/features/moderation/models/preprint-related-count-json-api.model.ts index 7b78a3871..6acc16e83 100644 --- a/src/app/features/moderation/models/preprint-related-count-json-api.model.ts +++ b/src/app/features/moderation/models/preprint-related-count-json-api.model.ts @@ -1,21 +1,31 @@ +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse, ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { PreprintProviderAttributesJsonApi } from '@osf/shared/models/provider/preprints-provider-json-api.model'; -export interface PreprintRelatedCountJsonApi { - id: string; - attributes: PreprintProviderAttributesJsonApi; - relationships: { - preprints: { - links: { - related: { - meta: { - accepted: number; - initial: number; - pending: number; - rejected: number; - withdrawn: number; - }; - }; +export type PreprintRelatedCountListResponseJsonApi = ListResponse; +export type PreprintRelatedCountItemResponseJsonApi = ItemResponse; + +export interface PreprintRelatedCountJsonApi extends JsonApiResource< + 'preprint-providers', + PreprintProviderAttributesJsonApi +> { + relationships: PreprintRelatedCountRelationshipsJsonApi; +} + +interface PreprintRelatedCountRelationshipsJsonApi { + preprints: { + links: { + related: { + meta: PreprintRelationshipMetaJsonApi; }; }; }; } + +interface PreprintRelationshipMetaJsonApi { + accepted: number; + initial: number; + pending: number; + rejected: number; + withdrawn: number; +} diff --git a/src/app/features/moderation/models/preprint-review-action-json-api.model.ts b/src/app/features/moderation/models/preprint-review-action-json-api.model.ts index ef2ce5fbf..552394353 100644 --- a/src/app/features/moderation/models/preprint-review-action-json-api.model.ts +++ b/src/app/features/moderation/models/preprint-review-action-json-api.model.ts @@ -1,49 +1,28 @@ -import { UserAttributesJsonApi, UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; +import { Embed } from '@osf/shared/models/common/json-api/embeds.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; +import { PreprintDataJsonApi } from '@osf/shared/models/preprints/preprint-json-api.model'; +import { PreprintProviderAttributesJsonApi } from '@osf/shared/models/provider/preprints-provider-json-api.model'; +import { UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export interface ReviewActionJsonApi { - id: string; - type: 'review-actions'; - attributes: ReviewActionAttributesJsonApi; - embeds: { - creator: UserDataErrorResponseJsonApi; - target: { - data: PreprintModelJsonApi; - }; - provider: { - data: ProviderModelJsonApi; - }; - }; +export type PreprintReviewActionListResponseJsonApi = ListResponse; + +export interface ReviewActionJsonApi extends JsonApiResource<'review-actions', ReviewActionAttributesJsonApi> { + embeds: ReviewActionEmbedsJsonApi; } -export interface ReviewActionAttributesJsonApi { - trigger: string; +interface ReviewActionAttributesJsonApi { + auto: boolean; comment: string; - from_state: string; - to_state: string; date_created: string; date_modified: string; - auto: boolean; -} - -export interface UserModelJsonApi { - id: string; - type: 'users'; - attributes: UserAttributesJsonApi; -} - -export interface PreprintModelJsonApi { - id: string; - type: 'preprints'; - attributes: PreprintAttributesJsonApi; -} - -export interface PreprintAttributesJsonApi { - title: string; + from_state: string; + to_state: string; + trigger: string; } -export interface ProviderModelJsonApi { - id: string; - attributes: { - name: string; - }; +interface ReviewActionEmbedsJsonApi { + creator: UserDataErrorResponseJsonApi; + provider: Embed>; + target: Embed; } diff --git a/src/app/features/moderation/models/preprint-submission-json-api.model.ts b/src/app/features/moderation/models/preprint-submission-json-api.model.ts index d18b87089..51509db33 100644 --- a/src/app/features/moderation/models/preprint-submission-json-api.model.ts +++ b/src/app/features/moderation/models/preprint-submission-json-api.model.ts @@ -1,30 +1,27 @@ -import { JsonApiResponseWithMeta, MetaJsonApi } from '@osf/shared/models/common/json-api.model'; +import { ListMetaJsonApi } from '@osf/shared/models/common/json-api/meta.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; -export type PreprintSubmissionResponseJsonApi = JsonApiResponseWithMeta< - PreprintSubmissionDataJsonApi[], - PreprintSubmissionMetaJsonApi, - null ->; +export type PreprintSubmissionResponseJsonApi = ListResponse & { + meta: PreprintSubmissionMetaJsonApi; +}; -export interface PreprintSubmissionDataJsonApi { - id: string; - attributes: PreprintSubmissionAttributesJsonApi; -} +export type PreprintSubmissionDataJsonApi = JsonApiResource<'preprints', PreprintSubmissionAttributesJsonApi>; -interface PreprintSubmissionMetaJsonApi extends MetaJsonApi { +interface PreprintSubmissionMetaJsonApi extends ListMetaJsonApi { reviews_state_counts: { - pending: number; accepted: number; + pending: number; rejected: number; withdrawn: number; }; } interface PreprintSubmissionAttributesJsonApi { + embargo_end_date: string; + embargoed: boolean; id: string; - title: string; - reviews_state: string; public: boolean; - embargoed: boolean; - embargo_end_date: string; + reviews_state: string; + title: string; } diff --git a/src/app/features/moderation/models/preprint-withdrawal-submission-json-api.model.ts b/src/app/features/moderation/models/preprint-withdrawal-submission-json-api.model.ts index c68a0c336..5430734b3 100644 --- a/src/app/features/moderation/models/preprint-withdrawal-submission-json-api.model.ts +++ b/src/app/features/moderation/models/preprint-withdrawal-submission-json-api.model.ts @@ -1,40 +1,36 @@ -import { JsonApiResponseWithMeta, MetaJsonApi } from '@osf/shared/models/common/json-api.model'; +import { Embed } from '@osf/shared/models/common/json-api/embeds.model'; +import { ListMetaJsonApi } from '@osf/shared/models/common/json-api/meta.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; +import { PreprintAttributesJsonApi } from '@osf/shared/models/preprints/preprint-json-api.model'; import { UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export type PreprintSubmissionWithdrawalResponseJsonApi = JsonApiResponseWithMeta< - PreprintWithdrawalSubmissionDataJsonApi[], - PreprintWithdrawalSubmissionMetaJsonApi, - null ->; +export type PreprintSubmissionWithdrawalResponseJsonApi = ListResponse & { + meta: PreprintWithdrawalSubmissionMetaJsonApi; +}; -export interface PreprintWithdrawalSubmissionDataJsonApi { - id: string; - attributes: PreprintWithdrawalSubmissionAttributesJsonApi; +export interface PreprintWithdrawalSubmissionDataJsonApi extends JsonApiResource< + 'preprint-withdrawal-submissions', + PreprintWithdrawalSubmissionAttributesJsonApi +> { embeds: PreprintWithdrawalSubmissionEmbedsJsonApi; } -interface PreprintWithdrawalSubmissionMetaJsonApi extends MetaJsonApi { +interface PreprintWithdrawalSubmissionMetaJsonApi extends ListMetaJsonApi { requests_state_counts: { - pending: number; accepted: number; + pending: number; rejected: number; }; } interface PreprintWithdrawalSubmissionAttributesJsonApi { comment: string; - machine_state: string; date_last_transitioned: string; + machine_state: string; } interface PreprintWithdrawalSubmissionEmbedsJsonApi { - target: { - data: { - id: string; - attributes: { - title: string; - }; - }; - }; creator: UserDataErrorResponseJsonApi; + target: Embed>; } diff --git a/src/app/features/moderation/models/registry-json-api.model.ts b/src/app/features/moderation/models/registry-json-api.model.ts index e8dd6c41e..1fbf11e9d 100644 --- a/src/app/features/moderation/models/registry-json-api.model.ts +++ b/src/app/features/moderation/models/registry-json-api.model.ts @@ -1,16 +1,14 @@ -import { ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; +import { ToManyRel } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { RegistrationNodeAttributesJsonApi } from '@osf/shared/models/registration/registration-node-json-api.model'; -export type RegistryResponseJsonApi = ResponseJsonApi; +export type RegistryResponseJsonApi = ListResponse; -export interface RegistryDataJsonApi { - id: string; - attributes: RegistrationNodeAttributesJsonApi; +export interface RegistryDataJsonApi extends JsonApiResource<'registrations', RegistrationNodeAttributesJsonApi> { embeds: RegistryEmbedsJsonApi; } -export interface RegistryEmbedsJsonApi { - schema_responses: { - data: { id: string }[]; - }; +interface RegistryEmbedsJsonApi { + schema_responses: ToManyRel<'schema-responses'>; } diff --git a/src/app/features/moderation/models/review-action-json-api.model.ts b/src/app/features/moderation/models/review-action-json-api.model.ts index a8d5be563..0384b3046 100644 --- a/src/app/features/moderation/models/review-action-json-api.model.ts +++ b/src/app/features/moderation/models/review-action-json-api.model.ts @@ -1,11 +1,10 @@ -import { JsonApiResponse } from '@osf/shared/models/common/json-api.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export type ReviewActionsResponseJsonApi = JsonApiResponse; +export type ReviewActionsResponseJsonApi = ListResponse; -export interface ReviewActionsDataJsonApi { - id: string; - attributes: ReviewActionAttributesJsonApi; +export interface ReviewActionDataJsonApi extends JsonApiResource<'review-actions', ReviewActionAttributesJsonApi> { embeds: ReviewActionEmbedsJsonApi; } diff --git a/src/app/features/moderation/services/moderators.service.ts b/src/app/features/moderation/services/moderators.service.ts index 3a184913f..3e201bdb6 100644 --- a/src/app/features/moderation/services/moderators.service.ts +++ b/src/app/features/moderation/services/moderators.service.ts @@ -3,10 +3,10 @@ import { forkJoin, map, Observable } from 'rxjs'; import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; +import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants/default-table-params.constants'; import { ResourceType } from '@osf/shared/enums/resource-type.enum'; import { parseSearchTotalCount } from '@osf/shared/helpers/search-total-count.helper'; import { MapResources } from '@osf/shared/mappers/search'; -import { JsonApiResponse } from '@osf/shared/models/common/json-api.model'; import { PaginatedData } from '@osf/shared/models/paginated-data.model'; import { IndexCardSearchResponseJsonApi } from '@osf/shared/models/search/index-card-search-json-api.model'; import { SearchUserDataModel } from '@osf/shared/models/user/search-user-data.model'; @@ -15,7 +15,13 @@ import { StringOrNull } from '@shared/helpers/types.helper'; import { AddModeratorType, ModeratorPermission } from '../enums'; import { ModerationMapper } from '../mappers'; -import { ModeratorAddModel, ModeratorDataJsonApi, ModeratorModel, ModeratorResponseJsonApi } from '../models'; +import { + ModeratorAddModel, + ModeratorDataJsonApi, + ModeratorItemResponseJsonApi, + ModeratorModel, + ModeratorResponseJsonApi, +} from '../models'; @Injectable({ providedIn: 'root', @@ -64,7 +70,7 @@ export class ModeratorsService { map((response) => ({ data: ModerationMapper.getModerators(response.data), totalCount: response.meta.total, - pageSize: response.meta.per_page, + pageSize: response.meta.per_page ?? DEFAULT_TABLE_PARAMS.rows, })) ); } @@ -76,7 +82,7 @@ export class ModeratorsService { const moderatorData = { data: ModerationMapper.toModeratorAddRequest(data, type) }; return this.jsonApiService - .post>(baseUrl, moderatorData) + .post(baseUrl, moderatorData) .pipe(map((moderator) => ModerationMapper.fromModeratorResponse(moderator.data))); } diff --git a/src/app/features/moderation/services/preprint-moderation.service.ts b/src/app/features/moderation/services/preprint-moderation.service.ts index a41c9906f..61672912a 100644 --- a/src/app/features/moderation/services/preprint-moderation.service.ts +++ b/src/app/features/moderation/services/preprint-moderation.service.ts @@ -3,7 +3,6 @@ import { catchError, forkJoin, map, Observable, of, switchMap } from 'rxjs'; import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; -import { ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; import { PaginatedData } from '@osf/shared/models/paginated-data.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; @@ -11,13 +10,14 @@ import { PreprintSubmissionsSort } from '../enums'; import { PreprintModerationMapper, RegistryModerationMapper } from '../mappers'; import { PreprintProviderModerationInfo, - PreprintRelatedCountJsonApi, + PreprintRelatedCountItemResponseJsonApi, + PreprintRelatedCountListResponseJsonApi, + PreprintReviewActionListResponseJsonApi, PreprintReviewActionModel, PreprintSubmissionResponseJsonApi, PreprintSubmissionWithdrawalResponseJsonApi, PreprintWithdrawalPaginatedData, ReviewAction, - ReviewActionJsonApi, ReviewActionsResponseJsonApi, } from '../models'; import { PreprintSubmissionPaginatedData } from '../models/preprint-submission.model'; @@ -37,7 +37,7 @@ export class PreprintModerationService { const baseUrl = `${this.apiUrl}/providers/preprints/?filter[permissions]=view_actions,set_up_moderation`; return this.jsonApiService - .get>(baseUrl) + .get(baseUrl) .pipe(map((response) => response.data.map((x) => PreprintModerationMapper.fromPreprintRelatedCounts(x)))); } @@ -45,7 +45,7 @@ export class PreprintModerationService { const baseUrl = `${this.apiUrl}/providers/preprints/${id}/?related_counts=true`; return this.jsonApiService - .get>(baseUrl) + .get(baseUrl) .pipe(map((response) => PreprintModerationMapper.fromPreprintRelatedCounts(response.data))); } @@ -53,7 +53,7 @@ export class PreprintModerationService { const baseUrl = `${this.apiUrl}/actions/reviews/?embed=provider&embed=target&page=${page}`; return this.jsonApiService - .get>(baseUrl) + .get(baseUrl) .pipe(map((response) => PreprintModerationMapper.fromResponseWithPagination(response))); } diff --git a/src/app/features/moderation/services/provider-subscription.service.ts b/src/app/features/moderation/services/provider-subscription.service.ts index 21277c50b..378022180 100644 --- a/src/app/features/moderation/services/provider-subscription.service.ts +++ b/src/app/features/moderation/services/provider-subscription.service.ts @@ -6,9 +6,11 @@ import { ENVIRONMENT } from '@core/provider/environment.provider'; import { SubscriptionFrequency } from '@osf/shared/enums/subscriptions/subscription-frequency.enum'; import { SubscriptionType } from '@osf/shared/enums/subscriptions/subscription-type.enum'; import { NotificationSubscriptionMapper } from '@osf/shared/mappers/notification-subscription.mapper'; -import { JsonApiResponse } from '@osf/shared/models/common/json-api.model'; import { NotificationSubscription } from '@osf/shared/models/notifications/notification-subscription.model'; -import { NotificationSubscriptionGetResponseJsonApi } from '@osf/shared/models/notifications/notification-subscription-json-api.model'; +import { + NotificationSubscriptionDataJsonApi, + NotificationSubscriptionsListResponseJsonApi, +} from '@osf/shared/models/notifications/notification-subscription-json-api.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; @Injectable({ @@ -24,9 +26,7 @@ export class ProviderSubscriptionService { getProviderSubscriptions(providerType: string, providerId: string): Observable { return this.jsonApiService - .get< - JsonApiResponse - >(this.providerUrl(providerType, providerId)) + .get(this.providerUrl(providerType, providerId)) .pipe( map((responses) => responses.data.map((response) => NotificationSubscriptionMapper.fromGetResponse(response))) ); @@ -47,7 +47,7 @@ export class ProviderSubscriptionService { }; return this.jsonApiService - .patch( + .patch( `${this.providerUrl(providerType, providerId)}${subscriptionId}/`, request ) diff --git a/src/app/features/moderation/store/collections-moderation/collections-moderation.model.ts b/src/app/features/moderation/store/collections-moderation/collections-moderation.model.ts index daa7cb0af..e5ab11a96 100644 --- a/src/app/features/moderation/store/collections-moderation/collections-moderation.model.ts +++ b/src/app/features/moderation/store/collections-moderation/collections-moderation.model.ts @@ -1,5 +1,5 @@ import { CollectionSubmissionReviewAction } from '@osf/features/moderation/models'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collection-submissions.model'; import { AsyncStateModel } from '@osf/shared/models/store/async-state.model'; import { AsyncStateWithTotalCount } from '@osf/shared/models/store/async-state-with-total-count.model'; diff --git a/src/app/features/my-projects/my-projects.component.ts b/src/app/features/my-projects/my-projects.component.ts index 8fd1df271..d541a1d69 100644 --- a/src/app/features/my-projects/my-projects.component.ts +++ b/src/app/features/my-projects/my-projects.component.ts @@ -32,7 +32,7 @@ import { SubHeaderComponent } from '@osf/shared/components/sub-header/sub-header import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants/default-table-params.constants'; import { SortOrder } from '@osf/shared/enums/sort-order.enum'; import { IS_MEDIUM } from '@osf/shared/helpers/breakpoints.tokens'; -import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources.model'; +import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources-item.model'; import { MyResourcesSearchFilters } from '@osf/shared/models/my-resources/my-resources-search-filters.model'; import { CustomDialogService } from '@osf/shared/services/custom-dialog.service'; import { ProjectRedirectDialogService } from '@osf/shared/services/project-redirect-dialog.service'; diff --git a/src/app/features/my-projects/services/project-download-options.service.spec.ts b/src/app/features/my-projects/services/project-download-options.service.spec.ts index 6b86d22c6..f04ceb8f4 100644 --- a/src/app/features/my-projects/services/project-download-options.service.spec.ts +++ b/src/app/features/my-projects/services/project-download-options.service.spec.ts @@ -53,7 +53,9 @@ describe('ProjectDownloadOptionsService', () => { beforeEach(() => { filesService = FilesServiceMock.simple(); - filesService.getRootFolders.mockReturnValue(of({ files: [osfFolder, googleDriveFolder] })); + filesService.getRootFolders.mockReturnValue( + of({ data: [osfFolder, googleDriveFolder], totalCount: 2, pageSize: 10 }) + ); filesService.getConfiguredStorageAddons.mockReturnValue(of([googleDriveAddon])); filesService.getFilesWithoutFiltering.mockReturnValue(of({ data: [], totalCount: 2, pageSize: 10 })); @@ -111,7 +113,9 @@ describe('ProjectDownloadOptionsService', () => { ...osfFolder, links: osfLinksWithoutFilesLink, } as FileFolderModel; - filesService.getRootFolders.mockReturnValue(of({ files: [osfFolderWithoutFilesLink, googleDriveFolder] })); + filesService.getRootFolders.mockReturnValue( + of({ data: [osfFolderWithoutFilesLink, googleDriveFolder], totalCount: 2, pageSize: 10 }) + ); await firstValueFrom(service.loadOptions('project-1')); diff --git a/src/app/features/my-projects/services/project-download-options.service.ts b/src/app/features/my-projects/services/project-download-options.service.ts index a170e4563..555bb70a3 100644 --- a/src/app/features/my-projects/services/project-download-options.service.ts +++ b/src/app/features/my-projects/services/project-download-options.service.ts @@ -61,7 +61,7 @@ export class ProjectDownloadOptionsService { configuredAddons: this.filesService.getConfiguredStorageAddons(projectId), }).pipe( switchMap(({ rootFoldersResponse, configuredAddons }) => - this.buildOptions(rootFoldersResponse.files, configuredAddons) + this.buildOptions(rootFoldersResponse.data, configuredAddons) ), map((options) => { this.optionsCache.set(projectId, options); diff --git a/src/app/features/preprints/mappers/preprint-providers.mapper.ts b/src/app/features/preprints/mappers/preprint-providers.mapper.ts index c9fa25ac2..bbb1eb94d 100644 --- a/src/app/features/preprints/mappers/preprint-providers.mapper.ts +++ b/src/app/features/preprints/mappers/preprint-providers.mapper.ts @@ -1,6 +1,6 @@ import { replaceBadEncodedChars } from '@osf/shared/helpers/format-bad-encoding.helper'; -import { BrandDataJsonApi } from '@osf/shared/models/brand/brand.json-api.model'; import { BrandModel } from '@osf/shared/models/brand/brand.model'; +import { BrandDataJsonApi } from '@osf/shared/models/brand/brand-json-api.model'; import { SubjectModel } from '@osf/shared/models/subject/subject.model'; import { SubjectDataJsonApi } from '@osf/shared/models/subject/subjects-json-api.model'; @@ -8,7 +8,7 @@ import { PreprintProviderDetails, PreprintProviderDetailsJsonApi, PreprintProvid export class PreprintProvidersMapper { static fromPreprintProviderDetailsGetResponse(response: PreprintProviderDetailsJsonApi): PreprintProviderDetails { - const brandRaw = response.embeds!.brand?.data; + const brandRaw = response.embeds?.brand?.data; return { id: response.id, name: replaceBadEncodedChars(response.attributes.name), @@ -32,7 +32,7 @@ export class PreprintProvidersMapper { }; } - static parseBrand(brandRaw: BrandDataJsonApi): BrandModel { + static parseBrand(brandRaw: BrandDataJsonApi | undefined): BrandModel { if (!brandRaw) { return { primaryColor: 'var(--osf-provider-primary-color)', diff --git a/src/app/features/preprints/mappers/preprints.mapper.ts b/src/app/features/preprints/mappers/preprints.mapper.ts index ed01f2be9..952817c24 100644 --- a/src/app/features/preprints/mappers/preprints.mapper.ts +++ b/src/app/features/preprints/mappers/preprints.mapper.ts @@ -2,18 +2,14 @@ import { StringOrNull } from '@osf/shared/helpers/types.helper'; import { ContributorsMapper } from '@osf/shared/mappers/contributors'; import { IdentifiersMapper } from '@osf/shared/mappers/identifiers.mapper'; import { LicensesMapper } from '@osf/shared/mappers/licenses.mapper'; -import { ApiData, JsonApiResponseWithMeta, ResponseJsonApi } from '@osf/shared/models/common/json-api.model'; +import { + PreprintDataJsonApi, + PreprintResponseJsonApi, + PreprintsListResponseJsonApi, +} from '@osf/shared/models/preprints/preprint-json-api.model'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; -import { - PreprintAttributesJsonApi, - PreprintEmbedsJsonApi, - PreprintLinksJsonApi, - PreprintMetaJsonApi, - PreprintModel, - PreprintRelationshipsJsonApi, - PreprintShortInfoWithTotalCount, -} from '../models'; +import { PreprintModel, PreprintShortInfoWithTotalCount } from '../models'; export class PreprintsMapper { static toCreatePayload(title: string, abstract: string, providerId: string) { @@ -36,9 +32,7 @@ export class PreprintsMapper { }; } - static fromPreprintJsonApi( - response: ApiData - ): PreprintModel { + static fromPreprintJsonApi(response: PreprintDataJsonApi): PreprintModel { return { id: response.id, dateCreated: response.attributes.date_created, @@ -81,21 +75,15 @@ export class PreprintsMapper { whyNoPrereg: response.attributes.why_no_prereg ? replaceBadEncodedChars(response.attributes.why_no_prereg) : null, preregLinks: response.attributes.prereg_links, preregLinkInfo: response.attributes.prereg_link_info, - preprintDoiLink: response.links.preprint_doi, - articleDoiLink: response.links.doi, + preprintDoiLink: response.links?.preprint_doi ?? '', + articleDoiLink: response.links?.doi ?? '', embeddedLicense: null, providerId: response.relationships?.provider?.data?.id, defaultLicenseId: response.attributes.default_license_id, }; } - static fromPreprintWithEmbedsJsonApi( - response: JsonApiResponseWithMeta< - ApiData, - PreprintMetaJsonApi, - null - > - ): PreprintModel { + static fromPreprintWithEmbedsJsonApi(response: PreprintResponseJsonApi): PreprintModel { const data = response.data; const links = response.data.links; const relationships = response?.data?.relationships; @@ -142,10 +130,12 @@ export class PreprintsMapper { whyNoPrereg: data.attributes.why_no_prereg ? replaceBadEncodedChars(data.attributes.why_no_prereg) : null, preregLinks: data.attributes.prereg_links, preregLinkInfo: data.attributes.prereg_link_info, - embeddedLicense: LicensesMapper.fromLicenseDataJsonApi(data.embeds?.license?.data), + embeddedLicense: data.embeds?.license?.data + ? LicensesMapper.fromLicenseDataJsonApi(data.embeds?.license?.data) + : null, identifiers: IdentifiersMapper.fromJsonApi(data.embeds?.identifiers), - preprintDoiLink: links.preprint_doi, - articleDoiLink: links.doi, + preprintDoiLink: links?.preprint_doi ?? '', + articleDoiLink: links?.doi ?? '', providerId: relationships?.provider?.data?.id, }; } @@ -170,11 +160,7 @@ export class PreprintsMapper { }; } - static fromMyPreprintJsonApi( - response: ResponseJsonApi< - ApiData[] - > - ): PreprintShortInfoWithTotalCount { + static fromMyPreprintJsonApi(response: PreprintsListResponseJsonApi): PreprintShortInfoWithTotalCount { return { data: response.data.map((preprintData) => ({ id: preprintData.id, diff --git a/src/app/features/preprints/models/index.ts b/src/app/features/preprints/models/index.ts index 5c556d995..e831133e1 100644 --- a/src/app/features/preprints/models/index.ts +++ b/src/app/features/preprints/models/index.ts @@ -1,5 +1,4 @@ export * from './preprint.model'; -export * from './preprint-json-api.model'; export * from './preprint-licenses-json-api.model'; export * from './preprint-provider.model'; export * from './preprint-provider-json-api.model'; diff --git a/src/app/features/preprints/models/preprint-licenses-json-api.model.ts b/src/app/features/preprints/models/preprint-licenses-json-api.model.ts index b1b1ba6f8..ae507a659 100644 --- a/src/app/features/preprints/models/preprint-licenses-json-api.model.ts +++ b/src/app/features/preprints/models/preprint-licenses-json-api.model.ts @@ -1,21 +1,18 @@ +import { ToOneRelData } from '@osf/shared/models/common/json-api/relationships.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { DataResponse } from '@osf/shared/models/common/json-api/responses.model'; import { LicenseRecordJsonApi } from '@osf/shared/models/license/licenses-json-api.model'; -export interface PreprintLicenseRelationshipJsonApi { - id: string; - type: 'licenses'; +export type PreprintLicensePayloadJsonApi = DataResponse; + +interface PreprintLicenseDataJsonApi extends JsonApiResource<'preprints', PreprintLicenseAttributesJsonApi> { + relationships: PreprintLicenseRelationshipsJsonApi; +} + +interface PreprintLicenseAttributesJsonApi { + license_record?: LicenseRecordJsonApi; } -export interface PreprintLicensePayloadJsonApi { - data: { - type: 'preprints'; - id: string; - relationships: { - license: { - data: PreprintLicenseRelationshipJsonApi; - }; - }; - attributes: { - license_record?: LicenseRecordJsonApi; - }; - }; +interface PreprintLicenseRelationshipsJsonApi { + license: ToOneRelData<'licenses'>; } diff --git a/src/app/features/preprints/models/preprint-provider-json-api.model.ts b/src/app/features/preprints/models/preprint-provider-json-api.model.ts index e71cc5ee2..0ed0cb67f 100644 --- a/src/app/features/preprints/models/preprint-provider-json-api.model.ts +++ b/src/app/features/preprints/models/preprint-provider-json-api.model.ts @@ -1,41 +1,50 @@ import { ReviewPermissions } from '@osf/shared/enums/review-permissions.enum'; import { StringOrNull } from '@osf/shared/helpers/types.helper'; -import { BrandDataJsonApi } from '@osf/shared/models/brand/brand.json-api.model'; +import { BrandDataJsonApi } from '@osf/shared/models/brand/brand-json-api.model'; +import { Embed } from '@osf/shared/models/common/json-api/embeds.model'; +import { ResourceLinksJsonApi } from '@osf/shared/models/common/json-api/links.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ItemResponse, ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { ProviderReviewsWorkflow } from '../enums'; import { PreprintWord } from './preprint-provider.model'; -export interface PreprintProviderDetailsJsonApi { - id: string; - type: 'preprint-providers'; - attributes: { - name: string; - description: string; - advisory_board: StringOrNull; - example: string; - domain: string; - footer_links: string; - preprint_word: PreprintWord; - permissions: ReviewPermissions[]; - assets: { - wide_white: string; - square_color_no_transparent: string; - favicon: string; - }; - allow_submissions: boolean; - assertions_enabled: boolean; - reviews_workflow: ProviderReviewsWorkflow | null; - facebook_app_id: StringOrNull; - reviews_comments_private: StringOrNull; - reviews_comments_anonymous: StringOrNull; - }; - embeds?: { - brand: { - data: BrandDataJsonApi; - }; - }; - links: { - iri: string; - }; +export type PreprintProviderResponseJsonApi = ItemResponse; +export type PreprintProvidersListResponseJsonApi = ListResponse; + +export interface PreprintProviderDetailsJsonApi extends JsonApiResource< + 'preprint-providers', + PreprintProviderAttributesJsonApi +> { + embeds?: PreprintProviderEmbedsJsonApi; + links: ResourceLinksJsonApi; +} + +interface PreprintProviderAttributesJsonApi { + advisory_board: StringOrNull; + allow_submissions: boolean; + assertions_enabled: boolean; + assets: PreprintProviderAssetsJsonApi; + description: string; + domain: string; + example: string; + facebook_app_id: StringOrNull; + footer_links: string; + name: string; + permissions: ReviewPermissions[]; + preprint_word: PreprintWord; + reviews_comments_anonymous: StringOrNull; + reviews_comments_private: StringOrNull; + reviews_workflow: ProviderReviewsWorkflow | null; +} + +interface PreprintProviderAssetsJsonApi { + favicon: string; + square_color_no_transparent: string; + wide_white: string; +} + +interface PreprintProviderEmbedsJsonApi { + brand?: Embed; } diff --git a/src/app/features/preprints/models/preprint-request-action-json-api.model.ts b/src/app/features/preprints/models/preprint-request-action-json-api.model.ts index 4c9e53bef..777fbb899 100644 --- a/src/app/features/preprints/models/preprint-request-action-json-api.model.ts +++ b/src/app/features/preprints/models/preprint-request-action-json-api.model.ts @@ -1,24 +1,25 @@ -import { JsonApiResponse } from '@osf/shared/models/common/json-api.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export type PreprintRequestActionsJsonApiResponse = JsonApiResponse; +export type PreprintRequestActionsJsonApiResponse = ListResponse; -export interface PreprintRequestActionDataJsonApi { - id: string; - type: 'preprint_request_actions'; - attributes: PreprintRequestActionsAttributesJsonApi; - embeds: PreprintRequestEmbedsJsonApi; +export interface PreprintRequestActionDataJsonApi extends JsonApiResource< + 'preprint_request_actions', + PreprintRequestActionAttributesJsonApi +> { + embeds: PreprintRequestActionEmbedsJsonApi; } -interface PreprintRequestActionsAttributesJsonApi { - trigger: string; +interface PreprintRequestActionAttributesJsonApi { comment: string; - from_state: string; - to_state: string; date_created: Date; date_modified: Date; + from_state: string; + to_state: string; + trigger: string; } -interface PreprintRequestEmbedsJsonApi { +interface PreprintRequestActionEmbedsJsonApi { creator: UserDataErrorResponseJsonApi; } diff --git a/src/app/features/preprints/models/preprint-request-json-api.model.ts b/src/app/features/preprints/models/preprint-request-json-api.model.ts index fca82bcde..0d406799b 100644 --- a/src/app/features/preprints/models/preprint-request-json-api.model.ts +++ b/src/app/features/preprints/models/preprint-request-json-api.model.ts @@ -1,23 +1,25 @@ -import { PreprintRequestMachineState, PreprintRequestType } from '@osf/features/preprints/enums'; -import { JsonApiResponse } from '@osf/shared/models/common/json-api.model'; +import { JsonApiResource } from '@osf/shared/models/common/json-api/resource.model'; +import { ListResponse } from '@osf/shared/models/common/json-api/responses.model'; import { UserDataErrorResponseJsonApi } from '@osf/shared/models/user/user-json-api.model'; -export type PreprintRequestsJsonApiResponse = JsonApiResponse; +import { PreprintRequestMachineState, PreprintRequestType } from '../enums'; -export interface PreprintRequestDataJsonApi { - id: string; - type: 'preprint_requests'; - attributes: PreprintRequestAttributesJsonApi; +export type PreprintRequestsJsonApiResponse = ListResponse; + +export interface PreprintRequestDataJsonApi extends JsonApiResource< + 'preprint_requests', + PreprintRequestAttributesJsonApi +> { embeds: PreprintRequestEmbedsJsonApi; } interface PreprintRequestAttributesJsonApi { - request_type: PreprintRequestType; - machine_state: PreprintRequestMachineState; comment: string; created: Date; - modified: Date; date_last_transitioned: Date; + machine_state: PreprintRequestMachineState; + modified: Date; + request_type: PreprintRequestType; } interface PreprintRequestEmbedsJsonApi { diff --git a/src/app/features/preprints/services/preprint-files.service.ts b/src/app/features/preprints/services/preprint-files.service.ts index 0f0de7945..804f32e47 100644 --- a/src/app/features/preprints/services/preprint-files.service.ts +++ b/src/app/features/preprints/services/preprint-files.service.ts @@ -4,22 +4,17 @@ import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { PreprintsMapper } from '@osf/features/preprints/mappers'; -import { - PreprintAttributesJsonApi, - PreprintFilesLinks, - PreprintLinksJsonApi, - PreprintModel, - PreprintRelationshipsJsonApi, -} from '@osf/features/preprints/models'; -import { ApiData } from '@osf/shared/models/common/json-api.model'; import { FileFolderModel } from '@osf/shared/models/files/file-folder.model'; import { FileFolderResponseJsonApi, FileFoldersResponseJsonApi, } from '@osf/shared/models/files/file-folder-json-api.model'; +import { PreprintDataJsonApi } from '@osf/shared/models/preprints/preprint-json-api.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; import { FilesMapper } from '@shared/mappers/files/files.mapper'; +import { PreprintFilesLinks, PreprintModel } from '../models'; + @Injectable({ providedIn: 'root', }) @@ -33,24 +28,21 @@ export class PreprintFilesService { updateFileRelationship(preprintId: string, fileId: string): Observable { return this.jsonApiService - .patch>( - `${this.apiUrl}/preprints/${preprintId}/`, - { - data: { - type: 'preprints', - id: preprintId, - attributes: {}, - relationships: { - primary_file: { - data: { - type: 'files', - id: fileId, - }, + .patch(`${this.apiUrl}/preprints/${preprintId}/`, { + data: { + type: 'preprints', + id: preprintId, + attributes: {}, + relationships: { + primary_file: { + data: { + type: 'files', + id: fileId, }, }, }, - } - ) + }, + }) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response))); } diff --git a/src/app/features/preprints/services/preprint-licenses.service.ts b/src/app/features/preprints/services/preprint-licenses.service.ts index 5d8a3a5f8..6f8de72cf 100644 --- a/src/app/features/preprints/services/preprint-licenses.service.ts +++ b/src/app/features/preprints/services/preprint-licenses.service.ts @@ -4,18 +4,14 @@ import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { PreprintsMapper } from '@osf/features/preprints/mappers'; -import { - PreprintAttributesJsonApi, - PreprintLicensePayloadJsonApi, - PreprintLinksJsonApi, - PreprintRelationshipsJsonApi, -} from '@osf/features/preprints/models'; +import { PreprintDataJsonApi } from '@osf/shared/models/preprints/preprint-json-api.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; import { LicensesMapper } from '@shared/mappers/licenses.mapper'; -import { ApiData } from '@shared/models/common/json-api.model'; import { LicenseModel, LicenseOptions } from '@shared/models/license/license.model'; import { LicensesResponseJsonApi } from '@shared/models/license/licenses-json-api.model'; +import { PreprintLicensePayloadJsonApi } from '../models'; + @Injectable({ providedIn: 'root', }) @@ -61,9 +57,7 @@ export class PreprintLicensesService { }; return this.jsonApiService - .patch< - ApiData - >(`${this.apiUrl}/preprints/${preprintId}/`, payload) + .patch(`${this.apiUrl}/preprints/${preprintId}/`, payload) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response))); } } diff --git a/src/app/features/preprints/services/preprint-providers.service.ts b/src/app/features/preprints/services/preprint-providers.service.ts index 3463e59ed..9e2f18f61 100644 --- a/src/app/features/preprints/services/preprint-providers.service.ts +++ b/src/app/features/preprints/services/preprint-providers.service.ts @@ -6,11 +6,11 @@ import { ENVIRONMENT } from '@core/provider/environment.provider'; import { PreprintProvidersMapper } from '@osf/features/preprints/mappers'; import { PreprintProviderDetails, - PreprintProviderDetailsJsonApi, + PreprintProviderResponseJsonApi, PreprintProviderShortInfo, + PreprintProvidersListResponseJsonApi, } from '@osf/features/preprints/models'; import { JsonApiService } from '@osf/shared/services/json-api.service'; -import { JsonApiResponse } from '@shared/models/common/json-api.model'; import { SubjectModel } from '@shared/models/subject/subject.model'; import { SubjectsResponseJsonApi } from '@shared/models/subject/subjects-json-api.model'; @@ -27,15 +27,13 @@ export class PreprintProvidersService { getPreprintProviderById(id: string): Observable { return this.jsonApiService - .get>(`${this.apiUrl}${id}/?embed=brand`) + .get(`${this.apiUrl}${id}/?embed=brand`) .pipe(map((response) => PreprintProvidersMapper.fromPreprintProviderDetailsGetResponse(response.data))); } getPreprintProvidersToAdvertise(): Observable { return this.jsonApiService - .get< - JsonApiResponse - >(`${this.apiUrl}?filter[advertise_on_discover_page]=true&reload=true`) + .get(`${this.apiUrl}?filter[advertise_on_discover_page]=true&reload=true`) .pipe( map((response) => PreprintProvidersMapper.toPreprintProviderShortInfoFromGetResponse( @@ -47,7 +45,7 @@ export class PreprintProvidersService { getPreprintProvidersAllowingSubmissions(): Observable { return this.jsonApiService - .get>(`${this.apiUrl}?filter[allow_submissions]=true`) + .get(`${this.apiUrl}?filter[allow_submissions]=true`) .pipe(map((response) => PreprintProvidersMapper.toPreprintProviderShortInfoFromGetResponse(response.data))); } diff --git a/src/app/features/preprints/services/preprints-projects.service.ts b/src/app/features/preprints/services/preprints-projects.service.ts index 1f1eed57b..a228863a2 100644 --- a/src/app/features/preprints/services/preprints-projects.service.ts +++ b/src/app/features/preprints/services/preprints-projects.service.ts @@ -5,22 +5,17 @@ import { inject, Injectable } from '@angular/core'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { Primitive, StringOrNull } from '@osf/shared/helpers/types.helper'; import { IdNameModel } from '@osf/shared/models/common/id-name.model'; -import { ApiData } from '@osf/shared/models/common/json-api.model'; import { CreateProjectPayloadJsoApi, NodeResponseJsonApi, NodesResponseJsonApi, } from '@osf/shared/models/nodes/nodes-json-api.model'; +import { PreprintDataJsonApi } from '@osf/shared/models/preprints/preprint-json-api.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; import { replaceBadEncodedChars } from '@shared/helpers/format-bad-encoding.helper'; import { PreprintsMapper } from '../mappers'; -import { - PreprintAttributesJsonApi, - PreprintLinksJsonApi, - PreprintModel, - PreprintRelationshipsJsonApi, -} from '../models'; +import { PreprintModel } from '../models'; @Injectable({ providedIn: 'root', @@ -70,24 +65,21 @@ export class PreprintsProjectsService { updatePreprintProjectRelationship(preprintId: string, projectId: string): Observable { return this.jsonApiService - .patch>( - `${this.apiUrl}/preprints/${preprintId}/`, - { - data: { - type: 'preprints', - id: preprintId, - attributes: {}, - relationships: { - node: { - data: { - type: 'nodes', - id: projectId, - }, + .patch(`${this.apiUrl}/preprints/${preprintId}/`, { + data: { + type: 'preprints', + id: preprintId, + attributes: {}, + relationships: { + node: { + data: { + type: 'nodes', + id: projectId, }, }, }, - } - ) + }, + }) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response))); } diff --git a/src/app/features/preprints/services/preprints.service.ts b/src/app/features/preprints/services/preprints.service.ts index 5216bf12d..d065f23d0 100644 --- a/src/app/features/preprints/services/preprints.service.ts +++ b/src/app/features/preprints/services/preprints.service.ts @@ -5,29 +5,25 @@ import { Router } from '@angular/router'; import { ENVIRONMENT } from '@core/provider/environment.provider'; import { RegistryModerationMapper } from '@osf/features/moderation/mappers'; -import { ReviewActionsResponseJsonApi } from '@osf/features/moderation/models'; +import { ReviewActionsResponseJsonApi } from '@osf/features/moderation/models/review-action-json-api.model'; import { PreprintRequestActionsMapper } from '@osf/features/preprints/mappers/preprint-request-actions.mapper'; import { PreprintRequestAction } from '@osf/features/preprints/models/preprint-request-action.model'; import { searchPreferencesToJsonApiQueryParams } from '@osf/shared/helpers/search-pref-to-json-api-query-params.helper'; import { StringOrNull } from '@osf/shared/helpers/types.helper'; import { - ApiData, - JsonApiResponse, - JsonApiResponseWithMeta, - ResponseJsonApi, -} from '@osf/shared/models/common/json-api.model'; + PreprintAttributesJsonApi, + PreprintDataJsonApi, + PreprintMetricsResponseJsonApi, + PreprintResponseJsonApi, + PreprintsListResponseJsonApi, +} from '@osf/shared/models/preprints/preprint-json-api.model'; import { SearchFilters } from '@osf/shared/models/search-filters.model'; import { JsonApiService } from '@osf/shared/services/json-api.service'; import { preprintSortFieldMap } from '../constants'; import { PreprintRequestMapper, PreprintsMapper } from '../mappers'; import { - PreprintAttributesJsonApi, - PreprintEmbedsJsonApi, - PreprintLinksJsonApi, - PreprintMetaJsonApi, PreprintModel, - PreprintRelationshipsJsonApi, PreprintRequest, PreprintRequestActionsJsonApiResponse, PreprintRequestsJsonApiResponse, @@ -67,76 +63,52 @@ export class PreprintsService { createPreprint(title: string, abstract: string, providerId: string) { const payload = PreprintsMapper.toCreatePayload(title, abstract, providerId); return this.jsonApiService - .post< - JsonApiResponse< - ApiData, - null - > - >(`${this.apiUrl}/preprints/`, payload) + .post(`${this.apiUrl}/preprints/`, payload) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response.data))); } getById(id: string) { return this.jsonApiService - .get< - JsonApiResponse< - ApiData, - null - > - >(`${this.apiUrl}/preprints/${id}/`) + .get(`${this.apiUrl}/preprints/${id}/`) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response.data))); } getByIdWithEmbeds(id: string) { const params = { 'embed[]': ['license', 'identifiers'] }; - return this.jsonApiService - .get< - JsonApiResponseWithMeta< - ApiData, - PreprintMetaJsonApi, - null - > - >(`${this.apiUrl}/preprints/${id}/`, params) - .pipe( - map((response) => PreprintsMapper.fromPreprintWithEmbedsJsonApi(response)), - catchError((error) => { - if (error.error?.errors?.[0]?.meta?.flagged_content) { - this.router.navigate(['/spam-content']); - } - return throwError(() => error); - }) - ); + + return this.jsonApiService.get(`${this.apiUrl}/preprints/${id}/`, params).pipe( + map((response) => PreprintsMapper.fromPreprintWithEmbedsJsonApi(response)), + catchError((error) => { + if (error.error?.errors?.[0]?.meta?.flagged_content) { + this.router.navigate(['/spam-content']); + } + return throwError(() => error); + }) + ); } getPreprintMetrics(id: string) { const params = { 'metrics[views]': 'total', 'metrics[downloads]': 'total' }; - return this.jsonApiService - .get< - JsonApiResponseWithMeta, PreprintMetaJsonApi, null> - >(`${this.apiUrl}/preprints/${id}/`, params) - .pipe( - map((response) => ({ - downloads: response.meta.metrics.downloads, - views: response.meta.metrics.views, - })) - ); + return this.jsonApiService.get(`${this.apiUrl}/preprints/${id}/`, params).pipe( + map((response) => ({ + downloads: response.meta.metrics.downloads, + views: response.meta.metrics.views, + })) + ); } updatePreprint(id: string, payload: Partial): Observable { const apiPayload = this.mapPreprintDomainToApiPayload(payload); return this.jsonApiService - .patch>( - `${this.apiUrl}/preprints/${id}/`, - { - data: { - type: 'preprints', - id, - attributes: apiPayload, - }, - } - ) + .patch(`${this.apiUrl}/preprints/${id}/`, { + data: { + type: 'preprints', + id, + attributes: apiPayload, + }, + }) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response))); } @@ -147,12 +119,7 @@ export class PreprintsService { createNewVersion(prevVersionPreprintId: string) { return this.jsonApiService - .post< - JsonApiResponse< - ApiData, - null - > - >(`${this.apiUrl}/preprints/${prevVersionPreprintId}/versions/`) + .post(`${this.apiUrl}/preprints/${prevVersionPreprintId}/versions/`) .pipe(map((response) => PreprintsMapper.fromPreprintJsonApi(response.data))); } @@ -168,9 +135,7 @@ export class PreprintsService { getPreprintVersionIds(preprintId: string): Observable { return this.jsonApiService - .get< - ResponseJsonApi[]> - >(`${this.apiUrl}/preprints/${preprintId}/versions/`) + .get(`${this.apiUrl}/preprints/${preprintId}/versions/`) .pipe(map((response) => response.data.map((data) => data.id))); } @@ -184,9 +149,7 @@ export class PreprintsService { searchPreferencesToJsonApiQueryParams(params, pageNumber, pageSize, filters, preprintSortFieldMap); return this.jsonApiService - .get< - ResponseJsonApi[]> - >(`${this.apiUrl}/users/me/preprints/`, params) + .get(`${this.apiUrl}/users/me/preprints/`, params) .pipe(map((response) => PreprintsMapper.fromMyPreprintJsonApi(response))); } diff --git a/src/app/features/profile/components/profile-information/profile-information.component.spec.ts b/src/app/features/profile/components/profile-information/profile-information.component.spec.ts index f8ec5857e..9718289a4 100644 --- a/src/app/features/profile/components/profile-information/profile-information.component.spec.ts +++ b/src/app/features/profile/components/profile-information/profile-information.component.spec.ts @@ -92,7 +92,7 @@ describe('ProfileInformationComponent', () => { it('should expose ORCID id only when verified', () => { setup({ ...MOCK_USER, - external_identity: { + externalIdentity: { ORCID: { id: '0000-0002-1825-0097', status: ExternalIdentityStatus.VERIFIED, @@ -106,7 +106,7 @@ describe('ProfileInformationComponent', () => { it('should return undefined ORCID when status is not verified', () => { setup({ ...MOCK_USER, - external_identity: { + externalIdentity: { ORCID: { id: '0000-0002-1825-0097', status: ExternalIdentityStatus.LINK, diff --git a/src/app/features/profile/components/profile-information/profile-information.component.ts b/src/app/features/profile/components/profile-information/profile-information.component.ts index 68b9edf81..e74d23b08 100644 --- a/src/app/features/profile/components/profile-information/profile-information.component.ts +++ b/src/app/features/profile/components/profile-information/profile-information.component.ts @@ -50,7 +50,7 @@ export class ProfileInformationComponent { userSocials = computed(() => mapUserSocials(this.currentUser()?.social, SOCIAL_LINKS)); orcidId = computed(() => { - const orcid = this.currentUser()?.external_identity?.ORCID; + const orcid = this.currentUser()?.externalIdentity?.ORCID; return orcid?.status?.toUpperCase() === ExternalIdentityStatus.VERIFIED ? orcid.id : undefined; }); diff --git a/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.spec.ts b/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.spec.ts index eef31eabb..9ee681704 100644 --- a/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.spec.ts +++ b/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.spec.ts @@ -10,7 +10,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SearchInputComponent } from '@osf/shared/components/search-input/search-input.component'; import { ResourceSearchMode } from '@osf/shared/enums/resource-search-mode.enum'; import { ResourceType } from '@osf/shared/enums/resource-type.enum'; -import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources.model'; +import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources-item.model'; import { MyResourcesSelectors } from '@osf/shared/stores/my-resources'; import { NodeLinksSelectors } from '@osf/shared/stores/node-links'; diff --git a/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.ts b/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.ts index 279a2bc55..4760056f0 100644 --- a/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.ts +++ b/src/app/features/project/overview/components/link-resource-dialog/link-resource-dialog.component.ts @@ -29,7 +29,7 @@ import { SearchInputComponent } from '@osf/shared/components/search-input/search import { DEFAULT_TABLE_PARAMS } from '@osf/shared/constants/default-table-params.constants'; import { ResourceSearchMode } from '@osf/shared/enums/resource-search-mode.enum'; import { ResourceType } from '@osf/shared/enums/resource-type.enum'; -import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources.model'; +import { MyResourcesItem } from '@osf/shared/models/my-resources/my-resources-item.model'; import { MyResourcesSearchFilters } from '@osf/shared/models/my-resources/my-resources-search-filters.model'; import { GetMyProjects, GetMyRegistrations, MyResourcesSelectors } from '@osf/shared/stores/my-resources'; import { CreateNodeLink, DeleteNodeLink, NodeLinksSelectors } from '@osf/shared/stores/node-links'; diff --git a/src/app/features/project/overview/components/overview-collections/overview-collections.component.html b/src/app/features/project/overview/components/overview-collections/overview-collections.component.html index ad246257a..cfbe47a3b 100644 --- a/src/app/features/project/overview/components/overview-collections/overview-collections.component.html +++ b/src/app/features/project/overview/components/overview-collections/overview-collections.component.html @@ -34,9 +34,7 @@

{{ 'project.overview.metadata.collection' | translate }}

@let cedarTemplate = cedarTemplateById().get(templateId) ?? null; @let attributes = - cedarRecord && cedarTemplate?.attributes?.template - ? getCedarAttributes(cedarRecord, cedarTemplate!) - : []; + cedarRecord && cedarTemplate?.template ? getCedarAttributes(cedarRecord, cedarTemplate!) : []; @if (attributes.length) {
diff --git a/src/app/features/project/overview/components/overview-collections/overview-collections.component.spec.ts b/src/app/features/project/overview/components/overview-collections/overview-collections.component.spec.ts index e0e8ec058..5a855273c 100644 --- a/src/app/features/project/overview/components/overview-collections/overview-collections.component.spec.ts +++ b/src/app/features/project/overview/components/overview-collections/overview-collections.component.spec.ts @@ -1,11 +1,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; -import { CedarMetadataDataTemplateJsonApi } from '@osf/features/metadata/models'; -import { CollectionSubmission } from '@osf/shared/models/collections/collections.model'; +import { CedarMetadataTemplateModel } from '@osf/features/metadata/models'; +import { CollectionSubmission } from '@osf/shared/models/collections/collection-submissions.model'; -import { CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK } from '@testing/mocks/cedar-metadata-data-template-json-api.mock'; -import { MOCK_CEDAR_METADATA_RECORD_DATA } from '@testing/mocks/cedar-metadata-record.mock'; +import { MOCK_CEDAR_METADATA_RECORD, MOCK_CEDAR_METADATA_TEMPLATE } from '@testing/mocks/cedar-metadata-domain.mock'; import { MOCK_COLLECTION_SUBMISSION_BASE, MOCK_COLLECTION_SUBMISSIONS, @@ -43,7 +42,7 @@ describe('OverviewCollectionsComponent', () => { ...s, collectionTitle: s.title, collectionId: `col-${s.id}`, - })) as CollectionSubmission[]; + })); fixture.componentRef.setInput('projectSubmissions', submissions); fixture.componentRef.setInput('isProjectSubmissionsLoading', true); fixture.detectChanges(); @@ -56,11 +55,10 @@ describe('OverviewCollectionsComponent', () => { ...MOCK_COLLECTION_SUBMISSION_BASE, requiredMetadataTemplateId: 'template-1', }; - const cedarTemplate: CedarMetadataDataTemplateJsonApi = - CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK as CedarMetadataDataTemplateJsonApi; + const cedarTemplate: CedarMetadataTemplateModel = MOCK_CEDAR_METADATA_TEMPLATE; fixture.componentRef.setInput('projectSubmissions', [cedarSubmission]); - fixture.componentRef.setInput('cedarRecords', [MOCK_CEDAR_METADATA_RECORD_DATA]); + fixture.componentRef.setInput('cedarRecords', [MOCK_CEDAR_METADATA_RECORD]); fixture.componentRef.setInput('cedarTemplates', [cedarTemplate]); fixture.detectChanges(); await fixture.whenStable(); @@ -88,10 +86,9 @@ describe('OverviewCollectionsComponent', () => { }); it('should extract key-value pairs from a cedar record using template field order and labels', () => { - const cedarTemplate: CedarMetadataDataTemplateJsonApi = - CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK as CedarMetadataDataTemplateJsonApi; + const cedarTemplate: CedarMetadataTemplateModel = MOCK_CEDAR_METADATA_TEMPLATE; - const result = component.getCedarAttributes(MOCK_CEDAR_METADATA_RECORD_DATA, cedarTemplate); + const result = component.getCedarAttributes(MOCK_CEDAR_METADATA_RECORD, cedarTemplate); expect(result).toContainEqual({ key: 'Project Name', label: 'Project Name', value: 'Test Project Name' }); }); diff --git a/src/app/features/project/overview/components/overview-collections/overview-collections.component.ts b/src/app/features/project/overview/components/overview-collections/overview-collections.component.ts index e07dc4016..7cd71d5c1 100644 --- a/src/app/features/project/overview/components/overview-collections/overview-collections.component.ts +++ b/src/app/features/project/overview/components/overview-collections/overview-collections.component.ts @@ -8,9 +8,9 @@ import { Tag } from 'primeng/tag'; import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core'; import { RouterLink } from '@angular/router'; -import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models'; +import { CedarMetadataRecordModel, CedarMetadataTemplateModel } from '@osf/features/metadata/models'; import { StopPropagationDirective } from '@osf/shared/directives/stop-propagation.directive'; -import { CollectionSubmission } from '@osf/shared/models/collections/collections.model'; +import { CollectionSubmission } from '@osf/shared/models/collections/collection-submissions.model'; import { KeyValueModel } from '@osf/shared/models/common/key-value.model'; import { CollectionStatusSeverityPipe } from '@osf/shared/pipes/collection-status-severity.pipe'; @@ -36,14 +36,14 @@ import { CollectionStatusSeverityPipe } from '@osf/shared/pipes/collection-statu export class OverviewCollectionsComponent { projectSubmissions = input(null); isProjectSubmissionsLoading = input(false); - cedarRecords = input(null); - cedarTemplates = input(null); + cedarRecords = input(null); + cedarTemplates = input(null); cedarRecordByTemplateId = computed(() => { const records = this.cedarRecords(); return new Map( records?.flatMap((record) => { - const templateId = record.relationships?.template?.data?.id; + const templateId = record.templateId; return templateId ? [[templateId, record] as const] : []; }) ?? [] ); @@ -54,9 +54,9 @@ export class OverviewCollectionsComponent { return new Map(templates?.map((t) => [t.id, t] as const) ?? []); }); - getCedarAttributes(record: CedarMetadataRecordData, template: CedarMetadataDataTemplateJsonApi): KeyValueModel[] { - const { order, propertyLabels } = template.attributes.template._ui; - const metadata = record.attributes.metadata as Record; + getCedarAttributes(record: CedarMetadataRecordModel, template: CedarMetadataTemplateModel): KeyValueModel[] { + const { order, propertyLabels } = template.template._ui; + const metadata = record.metadata as Record; const attributes: KeyValueModel[] = []; for (const key of order) { diff --git a/src/app/features/project/overview/mappers/project-overview.mapper.ts b/src/app/features/project/overview/mappers/project-overview.mapper.ts index c6fabdfe8..186b39b44 100644 --- a/src/app/features/project/overview/mappers/project-overview.mapper.ts +++ b/src/app/features/project/overview/mappers/project-overview.mapper.ts @@ -12,16 +12,13 @@ export class ProjectOverviewMapper { ...nodeAttributes, rootParentId: relationships?.root?.data?.id, parentId: relationships?.parent?.data?.id, - forksCount: relationships.forks?.links?.related?.meta - ? (relationships.forks?.links?.related?.meta['count'] as number) + forksCount: relationships?.forks?.links?.related?.meta + ? (relationships?.forks?.links?.related?.meta['count'] as number) : 0, - viewOnlyLinksCount: relationships.view_only_links?.links?.related?.meta - ? (relationships.view_only_links?.links?.related?.meta['count'] as number) + viewOnlyLinksCount: relationships?.view_only_links?.links?.related?.meta + ? (relationships?.view_only_links?.links?.related?.meta['count'] as number) : 0, - links: { - iri: data.links?.iri, - }, - licenseId: relationships.license?.data?.id, + licenseId: relationships?.license?.data?.id, }; } } diff --git a/src/app/features/project/overview/models/project-overview.model.ts b/src/app/features/project/overview/models/project-overview.model.ts index 2c155b330..f1bd65c38 100644 --- a/src/app/features/project/overview/models/project-overview.model.ts +++ b/src/app/features/project/overview/models/project-overview.model.ts @@ -1,12 +1,6 @@ -import { MetaJsonApi } from '@osf/shared/models/common/json-api.model'; import { ContributorModel } from '@osf/shared/models/contributors/contributor.model'; import { BaseNodeModel } from '@osf/shared/models/nodes/base-node.model'; -export interface ProjectOverviewWithMeta { - project: ProjectOverviewModel; - meta?: MetaJsonApi; -} - export interface ProjectOverviewModel extends BaseNodeModel { forksCount: number; viewOnlyLinksCount: number; @@ -14,9 +8,4 @@ export interface ProjectOverviewModel extends BaseNodeModel { rootParentId?: string; licenseId?: string; contributors?: ContributorModel[]; - links: ProjectOverviewLinksModel; -} - -interface ProjectOverviewLinksModel { - iri: string; } diff --git a/src/app/features/project/overview/services/project-overview.service.ts b/src/app/features/project/overview/services/project-overview.service.ts index 7133193be..5a0caba1e 100644 --- a/src/app/features/project/overview/services/project-overview.service.ts +++ b/src/app/features/project/overview/services/project-overview.service.ts @@ -12,7 +12,6 @@ import { LicensesMapper } from '@osf/shared/mappers/licenses.mapper'; import { BaseNodeMapper } from '@osf/shared/mappers/nodes'; import { NodePreprintMapper } from '@osf/shared/mappers/nodes/node-preprint.mapper'; import { NodeStorageMapper } from '@osf/shared/mappers/nodes/node-storage.mapper'; -import { JsonApiResponse } from '@osf/shared/models/common/json-api.model'; import { IdentifiersResponseJsonApi } from '@osf/shared/models/identifiers/identifier-json-api.model'; import { InstitutionsJsonApiResponse } from '@osf/shared/models/institutions/institution-json-api.model'; import { Institution } from '@osf/shared/models/institutions/institutions.model'; @@ -30,7 +29,7 @@ import { IdentifierModel } from '@shared/models/identifiers/identifier.model'; import { LicenseModel } from '@shared/models/license/license.model'; import { ProjectOverviewMapper } from '../mappers'; -import { PrivacyStatusModel, ProjectOverviewWithMeta } from '../models'; +import { PrivacyStatusModel, ProjectOverviewModel } from '../models'; @Injectable({ providedIn: 'root', @@ -43,13 +42,15 @@ export class ProjectOverviewService { return `${this.environment.apiDomainUrl}/v2`; } - getProjectById(projectId: string): Observable { + getProjectById(projectId: string): Observable> { const params: Record = { related_counts: 'forks,view_only_links' }; return this.jsonApiService.get(`${this.apiUrl}/nodes/${projectId}/`, params).pipe( map((response) => ({ - project: ProjectOverviewMapper.getProjectOverview(response.data), - meta: response.meta, + data: ProjectOverviewMapper.getProjectOverview(response.data), + totalCount: 1, + pageSize: 1, + isAnonymous: response.meta?.anonymous ?? false, })) ); } @@ -123,7 +124,7 @@ export class ProjectOverviewService { }; return this.jsonApiService - .post>(`${this.apiUrl}/nodes/`, payload) + .post(`${this.apiUrl}/nodes/`, payload) .pipe(map((response) => BaseNodeMapper.getNodeData(response.data))); } @@ -157,7 +158,7 @@ export class ProjectOverviewService { } return this.jsonApiService - .post>(`${this.apiUrl}/nodes/${projectId}/children/`, payload, params) + .post(`${this.apiUrl}/nodes/${projectId}/children/`, payload, params) .pipe( switchMap((response) => { const componentId = response.data.id; diff --git a/src/app/features/project/overview/store/project-overview.state.ts b/src/app/features/project/overview/store/project-overview.state.ts index 16a944ac1..e8799ccd1 100644 --- a/src/app/features/project/overview/store/project-overview.state.ts +++ b/src/app/features/project/overview/store/project-overview.state.ts @@ -58,11 +58,11 @@ export class ProjectOverviewState { tap((response) => { ctx.patchState({ project: { - data: response.project, + data: response.data, isLoading: false, error: null, }, - isAnonymous: response.meta?.anonymous ?? false, + isAnonymous: response.isAnonymous, }); }), catchError((error) => handleSectionError(ctx, 'project', error)) diff --git a/src/app/features/project/project-addons/components/connect-configured-addon/connect-configured-addon.component.ts b/src/app/features/project/project-addons/components/connect-configured-addon/connect-configured-addon.component.ts index 61af24cc2..b7907d439 100644 --- a/src/app/features/project/project-addons/components/connect-configured-addon/connect-configured-addon.component.ts +++ b/src/app/features/project/project-addons/components/connect-configured-addon/connect-configured-addon.component.ts @@ -25,9 +25,9 @@ import { OperationNames } from '@osf/shared/enums/operation-names.enum'; import { ProjectAddonsStepperValue } from '@osf/shared/enums/profile-addons-stepper.enum'; import { getAddonTypeString } from '@osf/shared/helpers/addon-type.helper'; import { AddonModel } from '@osf/shared/models/addons/addon.model'; -import { AuthorizedAddonRequestJsonApi } from '@osf/shared/models/addons/addon-json-api.model'; import { AddonTerm } from '@osf/shared/models/addons/addon-utils.model'; import { AuthorizedAccountModel } from '@osf/shared/models/addons/authorized-account.model'; +import { AuthorizedAddonRequestJsonApi } from '@osf/shared/models/addons/authorized-addon-json-api.model'; import { AddonFormService } from '@osf/shared/services/addons/addon-form.service'; import { AddonOAuthService } from '@osf/shared/services/addons/addon-oauth.service'; import { AddonOperationInvocationService } from '@osf/shared/services/addons/addon-operation-invocation.service'; @@ -156,7 +156,7 @@ export class ConnectConfiguredAddonComponent { } const openURL = new URL(addon.redirectUrl); openURL.searchParams.set('nodeIri', this.resourceUri()); - openURL.searchParams.set('userIri', this.addonsUserReference()[0]?.attributes.user_uri); + openURL.searchParams.set('userIri', this.addonsUserReference()[0]?.userUri); return openURL.toString(); }); diff --git a/src/app/features/project/project-addons/project-addons.component.html b/src/app/features/project/project-addons/project-addons.component.html index 3fcf71ec0..4d4691b15 100644 --- a/src/app/features/project/project-addons/project-addons.component.html +++ b/src/app/features/project/project-addons/project-addons.component.html @@ -1,4 +1,4 @@ - +
- - @if (isMaintenanceMode()) { -
-

{{ 'maintenance.title' | translate }}

-

{{ 'maintenance.message' | translate }}

-
- } { + if (isMaintenance) { + this.activate(); + } + }); + } + activate(): void { this._isActive.set(true); if (this.pollingSubscription) { diff --git a/src/testing/providers/maintenance-mode.service.mock.ts b/src/testing/providers/maintenance-mode.service.mock.ts index 7db5cdb40..fcea0a289 100644 --- a/src/testing/providers/maintenance-mode.service.mock.ts +++ b/src/testing/providers/maintenance-mode.service.mock.ts @@ -7,15 +7,17 @@ import { MaintenanceModeService } from '@core/services/maintenance-mode.service' export type MaintenanceModeServiceMockType = Partial & { activate: Mock<() => void>; deactivate: Mock<() => void>; + checkOnce: Mock<() => void>; isActive: Signal; }; export const MaintenanceModeServiceMock = { - simple() { + simple(isActive = false) { return { activate: vi.fn(), deactivate: vi.fn(), - isActive: signal(false).asReadonly(), + checkOnce: vi.fn(), + isActive: signal(isActive).asReadonly(), } as MaintenanceModeServiceMockType; }, };