diff --git a/CHANGELOG-Nns-Dapp-unreleased.md b/CHANGELOG-Nns-Dapp-unreleased.md index c3e62df3013..2e827fdcbd1 100644 --- a/CHANGELOG-Nns-Dapp-unreleased.md +++ b/CHANGELOG-Nns-Dapp-unreleased.md @@ -14,13 +14,8 @@ proposal is successful, the changes it released will be moved from this file to #### Added -- Show USD values of tokens. -- Reporting page for NNS Neurons and ICP transactions. - #### Changed -- Sorts launched projects in the Launchpad page from newest to oldest. - #### Deprecated #### Removed diff --git a/CHANGELOG-Nns-Dapp.md b/CHANGELOG-Nns-Dapp.md index 1cb21ceb65b..72881ed8a50 100644 --- a/CHANGELOG-Nns-Dapp.md +++ b/CHANGELOG-Nns-Dapp.md @@ -11,6 +11,21 @@ The NNS Dapp is released through proposals in the Network Nervous System. Theref Unreleased changes are added to `CHANGELOG-Nns-Dapp-unreleased.md` and moved here after a successful release. +## Proposal 134484 + +### Application + +#### Added + +- Show USD values of tokens. +- Reporting page for NNS Neurons and ICP transactions. + +#### Changed + +- Sorts launched projects in the Launchpad page from newest to oldest. + +### Operations + ## Proposal 134397 ### Application diff --git a/Cargo.lock b/Cargo.lock index ee148065220..a202878ecfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -500,9 +500,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.10" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c30ee7f886f296b6422c0ff017e89dd4f831521dfdcc76f3f71aae1ce817222" +checksum = "d04aa85a9ba2542bded33d1eff0ffb17cb98b1be8117e0a25e1ad8c62bedc881" dependencies = [ "anyhow", "binread", @@ -576,9 +576,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] @@ -597,9 +597,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1235,9 +1235,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fe-derive" @@ -1831,7 +1831,7 @@ dependencies = [ "hkdf", "pem", "rand", - "thiserror 2.0.5", + "thiserror 2.0.7", "zeroize", ] @@ -2010,7 +2010,7 @@ dependencies = [ "serde_cbor", "strum", "strum_macros", - "thiserror 2.0.5", + "thiserror 2.0.7", "zeroize", ] @@ -2089,7 +2089,7 @@ dependencies = [ "ic-protobuf", "serde", "serde_bytes", - "thiserror 2.0.5", + "thiserror 2.0.7", ] [[package]] @@ -2143,7 +2143,7 @@ dependencies = [ "num-traits", "serde", "serde_bytes", - "thiserror 2.0.5", + "thiserror 2.0.7", ] [[package]] @@ -2703,7 +2703,7 @@ dependencies = [ "candid", "ic-base-types", "serde", - "thiserror 2.0.5", + "thiserror 2.0.7", ] [[package]] @@ -3095,7 +3095,7 @@ dependencies = [ "serde_with", "strum", "strum_macros", - "thiserror 2.0.5", + "thiserror 2.0.7", "thousands", ] @@ -3616,9 +3616,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libflate" @@ -3852,7 +3852,7 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nns-dapp" -version = "2.0.97" +version = "2.0.98" dependencies = [ "anyhow", "base64 0.22.1", @@ -4083,7 +4083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.5", + "thiserror 2.0.7", "ucd-trie", ] @@ -4344,7 +4344,7 @@ dependencies = [ [[package]] name = "proposals" -version = "2.0.97" +version = "2.0.98" dependencies = [ "anyhow", "candid", @@ -4534,9 +4534,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] @@ -4739,15 +4739,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4817,18 +4817,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -4854,9 +4854,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -5028,7 +5028,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sns_aggregator" -version = "2.0.97" +version = "2.0.98" dependencies = [ "anyhow", "base64 0.22.1", @@ -5250,11 +5250,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.5" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643caef17e3128658ff44d85923ef2d28af81bb71e0d67bbfe1d76f19a73e053" +checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" dependencies = [ - "thiserror-impl 2.0.5", + "thiserror-impl 2.0.7", ] [[package]] @@ -5270,9 +5270,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.5" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995d0bbc9995d1f19d28b7215a9352b0fc3cd3a2d2ec95c2cadc485cdedbcdde" +checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 540208f471a..cb886ccfba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -version = "2.0.97" +version = "2.0.98" [workspace.dependencies] ic-cdk = "0.17.0" diff --git a/dfx.json b/dfx.json index f8160b0cc23..37bcd2873d3 100644 --- a/dfx.json +++ b/dfx.json @@ -1,5 +1,5 @@ { - "dfx": "0.24.2", + "dfx": "0.24.3", "canisters": { "nns-governance": { "type": "custom", @@ -441,7 +441,7 @@ "DIDC_VERSION": "didc 0.4.0", "POCKETIC_VERSION": "3.0.1", "CARGO_SORT_VERSION": "1.0.9", - "SNSDEMO_RELEASE": "release-2024-12-04", + "SNSDEMO_RELEASE": "release-2024-12-11", "IC_COMMIT_FOR_PROPOSALS": "release-2024-12-06_03-16-base", "IC_COMMIT_FOR_SNS_AGGREGATOR": "release-2024-12-06_03-16-base" }, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8167e9e6895..d605267b1ca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dfinity/nns-dapp", - "version": "2.0.97", + "version": "2.0.98", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@dfinity/nns-dapp", - "version": "2.0.97", + "version": "2.0.98", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@dfinity/agent": "^2.1.3", @@ -34,8 +34,8 @@ "@sveltejs/adapter-static": "^3.0.5", "@sveltejs/kit": "^2.8.3", "@sveltejs/vite-plugin-svelte": "^3.1.2", - "@testing-library/jest-dom": "^6.6.2", - "@testing-library/svelte": "^5.2.3", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/svelte": "^5.2.6", "@testing-library/user-event": "^14.5.2", "@types/wicg-file-system-access": "^2023.10.5", "@typescript-eslint/eslint-plugin": "^6.8.0", @@ -78,10 +78,11 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", - "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", - "dev": true + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz", + "integrity": "sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==", + "dev": true, + "license": "MIT" }, "node_modules/@ampproject/remapping": { "version": "2.3.0", @@ -1545,10 +1546,11 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz", - "integrity": "sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", + "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", "dev": true, + "license": "MIT", "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", @@ -1569,6 +1571,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1581,13 +1584,15 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@testing-library/svelte": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@testing-library/svelte/-/svelte-5.2.3.tgz", - "integrity": "sha512-y5eaD2Vp3hb729dAv3dOYNoZ9uNM0bQ0rd5AfXDWPvI+HiGmjl8ZMOuKzBopveyAkci1Kplb6kS53uZhPGEK+w==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@testing-library/svelte/-/svelte-5.2.6.tgz", + "integrity": "sha512-1Y8cEg/BtV4J6g9irkY0ksz+ueDFYLiikjTLiqvQPkOUeDzR4gg2zECBf8yrOrCy3e2TAOYMcaysFa0bQMyk1w==", "dev": true, + "license": "MIT", "dependencies": { "@testing-library/dom": "^10.0.0" }, @@ -1613,6 +1618,7 @@ "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12", "npm": ">=6" @@ -2689,7 +2695,8 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cssesc": { "version": "3.0.0", @@ -3734,6 +3741,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4057,7 +4065,8 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -4209,6 +4218,7 @@ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5021,6 +5031,7 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, + "license": "MIT", "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" @@ -5448,6 +5459,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, + "license": "MIT", "dependencies": { "min-indent": "^1.0.0" }, @@ -6498,9 +6510,9 @@ "dev": true }, "@adobe/css-tools": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", - "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz", + "integrity": "sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==", "dev": true }, "@ampproject/remapping": { @@ -7411,9 +7423,9 @@ } }, "@testing-library/jest-dom": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz", - "integrity": "sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", + "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", "dev": true, "requires": { "@adobe/css-tools": "^4.4.0", @@ -7444,9 +7456,9 @@ } }, "@testing-library/svelte": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@testing-library/svelte/-/svelte-5.2.3.tgz", - "integrity": "sha512-y5eaD2Vp3hb729dAv3dOYNoZ9uNM0bQ0rd5AfXDWPvI+HiGmjl8ZMOuKzBopveyAkci1Kplb6kS53uZhPGEK+w==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@testing-library/svelte/-/svelte-5.2.6.tgz", + "integrity": "sha512-1Y8cEg/BtV4J6g9irkY0ksz+ueDFYLiikjTLiqvQPkOUeDzR4gg2zECBf8yrOrCy3e2TAOYMcaysFa0bQMyk1w==", "dev": true, "requires": { "@testing-library/dom": "^10.0.0" diff --git a/frontend/package.json b/frontend/package.json index 6773a0d980c..832bb56d19b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "@dfinity/nns-dapp", - "version": "2.0.97", + "version": "2.0.98", "private": true, "license": "SEE LICENSE IN LICENSE.md", "scripts": { @@ -36,8 +36,8 @@ "@sveltejs/adapter-static": "^3.0.5", "@sveltejs/kit": "^2.8.3", "@sveltejs/vite-plugin-svelte": "^3.1.2", - "@testing-library/jest-dom": "^6.6.2", - "@testing-library/svelte": "^5.2.3", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/svelte": "^5.2.6", "@testing-library/user-event": "^14.5.2", "@types/wicg-file-system-access": "^2023.10.5", "@typescript-eslint/eslint-plugin": "^6.8.0", diff --git a/frontend/src/lib/components/accounts/SelectNetworkDropdown.svelte b/frontend/src/lib/components/accounts/SelectNetworkDropdown.svelte index 4a1841e323b..796b6b1bfa8 100644 --- a/frontend/src/lib/components/accounts/SelectNetworkDropdown.svelte +++ b/frontend/src/lib/components/accounts/SelectNetworkDropdown.svelte @@ -59,7 +59,7 @@ testId="select-network-dropdown" > {$i18n.accounts.select_network} {$i18n.accounts.network_icp} -
+
{/if}
{accountName}
diff --git a/frontend/src/lib/components/common/EmptyCards.svelte b/frontend/src/lib/components/common/EmptyCards.svelte index 5c22cb7b3ba..565531b1430 100644 --- a/frontend/src/lib/components/common/EmptyCards.svelte +++ b/frontend/src/lib/components/common/EmptyCards.svelte @@ -4,19 +4,19 @@
-
+
-
+
-
+
-
+
-
+
diff --git a/frontend/src/lib/components/neuron-detail/NnsNeuronVotingPowerSection.svelte b/frontend/src/lib/components/neuron-detail/NnsNeuronVotingPowerSection.svelte index 82d505c87c1..a95bb966e8a 100644 --- a/frontend/src/lib/components/neuron-detail/NnsNeuronVotingPowerSection.svelte +++ b/frontend/src/lib/components/neuron-detail/NnsNeuronVotingPowerSection.svelte @@ -3,6 +3,7 @@ import { i18n } from "$lib/stores/i18n"; import { replacePlaceholders } from "$lib/utils/i18n.utils"; import { + activityMultiplier, ageMultiplier, dissolveDelayMultiplier, formatVotingPower, @@ -41,15 +42,22 @@

{$i18n.neuron_detail.calculated_as}

-

- {$i18n.neuron_detail.voting_power_section_calculation_generic} +

+ {$ENABLE_PERIODIC_FOLLOWING_CONFIRMATION + ? $i18n.neuron_detail.voting_power_section_calculation_generic_new + : $i18n.neuron_detail.voting_power_section_calculation_generic}

{$i18n.neuron_detail.this_neuron_calculation}

{replacePlaceholders( - $i18n.neuron_detail.voting_power_section_calculation_specific, + $ENABLE_PERIODIC_FOLLOWING_CONFIRMATION + ? $i18n.neuron_detail.voting_power_section_calculation_specific_new + : $i18n.neuron_detail.voting_power_section_calculation_specific, { $stake: formatTokenE8s({ value: neuronStake(neuron), @@ -59,6 +67,7 @@ $dissolveMultiplier: dissolveDelayMultiplier( neuron.dissolveDelaySeconds ).toFixed(2), + $activityMultiplier: activityMultiplier(neuron).toFixed(2), $votingPower: formatVotingPower(neuron.votingPower), } )} diff --git a/frontend/src/lib/components/neurons/NeuronsTable/NeuronStakeCell.svelte b/frontend/src/lib/components/neurons/NeuronsTable/NeuronStakeCell.svelte index 97f2e8380a1..c956b021739 100644 --- a/frontend/src/lib/components/neurons/NeuronsTable/NeuronStakeCell.svelte +++ b/frontend/src/lib/components/neurons/NeuronsTable/NeuronStakeCell.svelte @@ -1,12 +1,18 @@

- + {#if $ENABLE_USD_VALUES_FOR_NEURONS} + + {:else} + + {/if}
diff --git a/frontend/src/lib/components/staking/ProjectStakeCell.svelte b/frontend/src/lib/components/staking/ProjectStakeCell.svelte index bcf75d6c8b4..2443fac7019 100644 --- a/frontend/src/lib/components/staking/ProjectStakeCell.svelte +++ b/frontend/src/lib/components/staking/ProjectStakeCell.svelte @@ -11,8 +11,7 @@
{#if !(rowData.stake instanceof TokenAmountV2) || rowData.stake.toUlps() > 0} {#if $ENABLE_USD_VALUES_FOR_NEURONS} - + {:else} {/if} diff --git a/frontend/src/lib/components/tokens/TokensTable/TokenBalanceCell.svelte b/frontend/src/lib/components/tokens/TokensTable/TokenBalanceCell.svelte index aab0522756f..4b9b28e8f4b 100644 --- a/frontend/src/lib/components/tokens/TokensTable/TokenBalanceCell.svelte +++ b/frontend/src/lib/components/tokens/TokensTable/TokenBalanceCell.svelte @@ -22,8 +22,10 @@ > {:else if isUserTokenData(rowData)} {#if $ENABLE_USD_VALUES} - + {:else} {/if} diff --git a/frontend/src/lib/components/ui/ProposalStatusTag.svelte b/frontend/src/lib/components/ui/ProposalStatusTag.svelte index 99e93d2e23e..f06a2cbf588 100644 --- a/frontend/src/lib/components/ui/ProposalStatusTag.svelte +++ b/frontend/src/lib/components/ui/ProposalStatusTag.svelte @@ -26,7 +26,7 @@ class="actionable-status-badge" role="status" transition:scale={{ duration: 250, easing: cubicOut }} - /> + >
{/if} diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 67a1061465d..565336b7380 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -192,7 +192,11 @@ "error_csv_generation": "Failed to generate CSV file", "error_file_system_access": "Unable to save file. Please check your permissions.", "error_neurons": "There was an error exporting the neurons. Please try again.", - "error_transactions": "There was an error exporting the transactions. Please try again." + "error_transactions": "There was an error exporting the transactions. Please try again.", + "range_filter_title": "Reporting Date Range", + "range_filter_all": "All transactions", + "range_last_year": "Last year", + "range_year_to_date": "Year to date" }, "auth": { "login": "Sign in with Internet Identity", @@ -661,8 +665,10 @@ "voting_power_section_description_expanded_zero_nns": "The dissolve delay must be at least 6 months for the neuron to have voting power. Learn more about voting power on the dashboard.", "calculated_as": "Calculated as:", "voting_power_section_calculation_generic": "voting_power = (staked_amount + staked_maturity) × (1 + age_bonus) × (1 + dissolve_delay_bonus)", + "voting_power_section_calculation_generic_new": "voting_power = (staked_amount + staked_maturity) × (1 + age_bonus) × (1 + dissolve_delay_bonus) × activity_multiplier", "this_neuron_calculation": "For this neuron, the calculation is:", "voting_power_section_calculation_specific": "voting_power = ($stake + $maturityStaked) × $ageMultiplier × $dissolveMultiplier = $votingPower", + "voting_power_section_calculation_specific_new": "voting_power = ($stake + $maturityStaked) × $ageMultiplier × $dissolveMultiplier × $activityMultiplier = $votingPower", "maturity_section_description": "Earn rewards by voting on proposals and/or following active neurons.", "staked_description": "Staked", "nns_staked_maturity_tooltip": "Staked maturity contributes to the neuron’s voting power, but cannot be spawned into a new neuron.", diff --git a/frontend/src/lib/modals/neurons/SplitNnsNeuronModal.svelte b/frontend/src/lib/modals/neurons/SplitNnsNeuronModal.svelte index e2fe445378d..4a2d1b0c8ca 100644 --- a/frontend/src/lib/modals/neurons/SplitNnsNeuronModal.svelte +++ b/frontend/src/lib/modals/neurons/SplitNnsNeuronModal.svelte @@ -1,4 +1,4 @@ - -
+
diff --git a/frontend/src/tests/lib/services/reporting.services.spec.ts b/frontend/src/tests/lib/services/reporting.services.spec.ts index ed0a9e10a86..75170720fa0 100644 --- a/frontend/src/tests/lib/services/reporting.services.spec.ts +++ b/frontend/src/tests/lib/services/reporting.services.spec.ts @@ -9,7 +9,10 @@ import { mockMainAccount, mockSubAccount, } from "$tests/mocks/icp-accounts.store.mock"; -import { createTransactionWithId } from "$tests/mocks/icp-transactions.mock"; +import { + createTransactionWithId, + dateToNanoSeconds, +} from "$tests/mocks/icp-transactions.mock"; import { mockNeuron } from "$tests/mocks/neurons.mock"; import type { SignIdentity } from "@dfinity/agent"; @@ -114,14 +117,14 @@ describe("reporting service", () => { it("should handle errors and return accumulated transactions", async () => { const firstBatch = [ - createTransactionWithId({ id: 1n }), + createTransactionWithId({ id: 3n }), createTransactionWithId({ id: 2n }), ]; spyGetTransactions .mockResolvedValueOnce({ transactions: firstBatch, - oldestTxId: 2000n, + oldestTxId: 1n, }) .mockRejectedValueOnce(new Error("API Error")); @@ -133,6 +136,239 @@ describe("reporting service", () => { expect(result).toEqual(firstBatch); expect(spyGetTransactions).toHaveBeenCalledTimes(2); }); + + it('should filter "to" the provided date', async () => { + const allTransactions = [ + createTransactionWithId({ + id: 3n, + timestamp: new Date("2023-01-02T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 2n, + timestamp: new Date("2023-01-01T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 1n, + timestamp: new Date("2022-12-31T00:00:00.000Z"), + }), + ]; + + spyGetTransactions.mockResolvedValue({ + transactions: allTransactions, + oldestTxId: 1n, + }); + + const result = await getAllTransactionsFromAccountAndIdentity({ + accountId: mockAccountId, + identity: mockSignInIdentity, + range: { + to: dateToNanoSeconds(new Date("2023-01-01T00:00:00.000Z")), + }, + }); + + expect(result).toHaveLength(2); + expect(result).toEqual(allTransactions.slice(1)); + expect(spyGetTransactions).toHaveBeenCalledTimes(1); + }); + + it('should filter "from" the provided date', async () => { + const allTransactions = [ + createTransactionWithId({ + id: 3n, + timestamp: new Date("2023-01-02T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 2n, + timestamp: new Date("2023-01-01T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 1n, + timestamp: new Date("2022-12-31T00:00:00.000Z"), + }), + ]; + + spyGetTransactions.mockResolvedValue({ + transactions: allTransactions, + oldestTxId: 1n, + }); + + const result = await getAllTransactionsFromAccountAndIdentity({ + accountId: mockAccountId, + identity: mockSignInIdentity, + range: { + from: dateToNanoSeconds(new Date("2023-01-01T00:00:00.000Z")), + }, + }); + + expect(result).toHaveLength(2); + expect(result).toEqual(allTransactions.slice(0, 2)); + expect(spyGetTransactions).toHaveBeenCalledTimes(1); + }); + + it("should handle date range where no transactions match", async () => { + const allTransactions = [ + createTransactionWithId({ + id: 3n, + timestamp: new Date("2023-01-02T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 2n, + timestamp: new Date("2022-12-30T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 1n, + timestamp: new Date("2022-12-29T00:00:00.000Z"), + }), + ]; + + spyGetTransactions.mockResolvedValue({ + transactions: allTransactions, + oldestTxId: 1n, + }); + + const result = await getAllTransactionsFromAccountAndIdentity({ + accountId: mockAccountId, + identity: mockSignInIdentity, + range: { + to: dateToNanoSeconds(new Date("2023-01-01T00:00:00.000Z")), + from: dateToNanoSeconds(new Date("2022-12-31T00:00:00.000Z")), + }, + }); + + expect(result).toHaveLength(0); + expect(spyGetTransactions).toHaveBeenCalledTimes(1); + }); + + it('should return early if the last transaction is in the current page is older than "from" date', async () => { + const allTransactions = [ + createTransactionWithId({ + id: 3n, + timestamp: new Date("2023-01-02T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 2n, + timestamp: new Date("2022-12-31T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 1n, + timestamp: new Date("2022-12-30T00:00:00.000Z"), + }), + ]; + const firstBatchOfMockTransactions = allTransactions.slice(0, 2); + const secondBatchOfMockTransactions = allTransactions.slice(2); + + spyGetTransactions + .mockResolvedValueOnce({ + transactions: firstBatchOfMockTransactions, + oldestTxId: 1n, + }) + .mockResolvedValueOnce({ + transactions: secondBatchOfMockTransactions, + oldestTxId: 1n, + }); + + const result = await getAllTransactionsFromAccountAndIdentity({ + accountId: mockAccountId, + identity: mockSignInIdentity, + range: { + from: dateToNanoSeconds(new Date("2023-01-01T00:00:00.000Z")), + }, + }); + + expect(result).toHaveLength(1); + expect(result).toEqual(allTransactions.slice(0, 1)); + expect(spyGetTransactions).toHaveBeenCalledTimes(1); + }); + + it('should handle a range with both "from" and "to" dates', async () => { + const allTransactions = [ + createTransactionWithId({ + id: 6n, + timestamp: new Date("2023-02-02T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 5n, + timestamp: new Date("2023-01-01T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 4n, + timestamp: new Date("2022-12-31T10:00:00.000Z"), + }), + createTransactionWithId({ + id: 3n, + timestamp: new Date("2022-12-31T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 2n, + timestamp: new Date("2022-12-30T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 1n, + timestamp: new Date("2022-11-20T00:00:00.000Z"), + }), + ]; + const firstBatchOfMockTransactions = allTransactions.slice(0, 3); + const secondBatchOfMockTransactions = allTransactions.slice(3, 6); + + spyGetTransactions + .mockResolvedValueOnce({ + transactions: firstBatchOfMockTransactions, + oldestTxId: 1n, + }) + .mockResolvedValueOnce({ + transactions: secondBatchOfMockTransactions, + oldestTxId: 1n, + }); + + const result = await getAllTransactionsFromAccountAndIdentity({ + accountId: mockAccountId, + identity: mockSignInIdentity, + range: { + to: dateToNanoSeconds(new Date("2023-01-02T00:00:00.000Z")), + from: dateToNanoSeconds(new Date("2022-11-30T00:00:00.000Z")), + }, + }); + expect(result).toHaveLength(4); + expect(result).toEqual(allTransactions.slice(1, -1)); + expect(spyGetTransactions).toHaveBeenCalledTimes(2); + }); + + it("should filter the transactions even if one call fails", async () => { + const firstBatchOfMockTransactions = [ + createTransactionWithId({ + id: 6n, + timestamp: new Date("2023-02-02T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 5n, + timestamp: new Date("2023-01-01T00:00:00.000Z"), + }), + createTransactionWithId({ + id: 4n, + timestamp: new Date("2022-12-31T10:00:00.000Z"), + }), + ]; + spyGetTransactions + .mockResolvedValueOnce({ + transactions: firstBatchOfMockTransactions, + oldestTxId: 3n, + }) + .mockRejectedValueOnce(new Error("API Error")); + const result = await getAllTransactionsFromAccountAndIdentity({ + accountId: mockAccountId, + identity: mockSignInIdentity, + range: { + to: dateToNanoSeconds(new Date("2023-01-02T00:00:00.000Z")), + from: dateToNanoSeconds(new Date("2022-11-30T00:00:00.000Z")), + }, + }); + expect(result).toHaveLength(2); + expect(result).toEqual([ + firstBatchOfMockTransactions[1], + firstBatchOfMockTransactions[2], + ]); + expect(spyGetTransactions).toHaveBeenCalledTimes(2); + }); }); describe("getAccountTransactionsConcurrently", () => { diff --git a/frontend/src/tests/lib/utils/neuron.utils.spec.ts b/frontend/src/tests/lib/utils/neuron.utils.spec.ts index a61069968ff..66ada91ed88 100644 --- a/frontend/src/tests/lib/utils/neuron.utils.spec.ts +++ b/frontend/src/tests/lib/utils/neuron.utils.spec.ts @@ -18,6 +18,7 @@ import { neuronsStore } from "$lib/stores/neurons.store"; import { nowInSeconds } from "$lib/utils/date.utils"; import { enumValues } from "$lib/utils/enum.utils"; import { + activityMultiplier, ageMultiplier, allHaveSameFollowees, ballotsWithDefinedProposal, @@ -291,6 +292,67 @@ describe("neuron-utils", () => { }); }); + describe("activityMultiplier", () => { + it("returns 0 when decidingVotingPower is 0", () => { + expect( + activityMultiplier({ + ...mockNeuron, + fullNeuron: { + ...mockFullNeuron, + decidingVotingPower: 0n, + potentialVotingPower: 0n, + }, + }) + ).toBe(0); + }); + + it("returns 0 when potentialVotingPower is 0", () => { + expect( + activityMultiplier({ + ...mockNeuron, + fullNeuron: { + ...mockFullNeuron, + decidingVotingPower: 100_000_000n, + potentialVotingPower: 0n, + }, + }) + ).toBe(0); + }); + + it("calculates the multiplier", () => { + expect( + activityMultiplier({ + ...mockNeuron, + fullNeuron: { + ...mockFullNeuron, + decidingVotingPower: 200_000_000n, + potentialVotingPower: 200_000_000n, + }, + }) + ).toBe(1); + expect( + activityMultiplier({ + ...mockNeuron, + fullNeuron: { + ...mockFullNeuron, + decidingVotingPower: 100_000_000n, + potentialVotingPower: 200_000_000n, + }, + }) + ).toBe(0.5); + expect( + activityMultiplier({ + ...mockNeuron, + fullNeuron: { + ...mockFullNeuron, + decidingVotingPower: 20_000n, + potentialVotingPower: 200_000_000n, + }, + }) + ).toBe(0.0001); + }); + }); + describe("bonusMultiplier", () => { it("should return the multiplier", () => { expect( diff --git a/frontend/src/tests/lib/utils/neurons-table.utils.spec.ts b/frontend/src/tests/lib/utils/neurons-table.utils.spec.ts index b5262e6d04f..decab7926af 100644 --- a/frontend/src/tests/lib/utils/neurons-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/neurons-table.utils.spec.ts @@ -1,3 +1,4 @@ +import { LEDGER_CANISTER_ID } from "$lib/constants/canister-ids.constants"; import { HOTKEY_PERMISSIONS } from "$lib/constants/sns-neurons.constants"; import { compareByDissolveDelay, @@ -16,11 +17,13 @@ import { mockNeuron, mockTableNeuron } from "$tests/mocks/neurons.mock"; import { createMockSnsNeuron } from "$tests/mocks/sns-neurons.mock"; import { mockSnsToken } from "$tests/mocks/sns-projects.mock"; import { NeuronState, type NeuronInfo } from "@dfinity/nns"; +import { Principal } from "@dfinity/principal"; import type { SnsNeuron } from "@dfinity/sns"; import { ICPToken, TokenAmountV2 } from "@dfinity/utils"; describe("neurons-table.utils", () => { const now = new Date("2022-01-01T15:26:47Z"); + const icpPrice = 10; const makeStake = (amount: bigint) => TokenAmountV2.fromUlps({ @@ -28,6 +31,9 @@ describe("neurons-table.utils", () => { token: ICPToken, }); + const makeUsdStake = (amount: bigint) => + (Number(amount) * icpPrice) / 100_000_000; + beforeEach(() => { vi.useFakeTimers().setSystemTime(now); }); @@ -54,6 +60,7 @@ describe("neurons-table.utils", () => { domKey: "42", neuronId: "42", stake: makeStake(defaultStake), + stakeInUsd: makeUsdStake(defaultStake), availableMaturity: 0n, stakedMaturity: 0n, dissolveDelaySeconds: defaultDissolveDelaySeconds, @@ -67,6 +74,9 @@ describe("neurons-table.utils", () => { neuronInfos, identity: mockIdentity, accounts: mockAccountsStoreData, + icpSwapUsdPrices: { + [LEDGER_CANISTER_ID.toText()]: icpPrice, + }, i18n: en, }); @@ -105,6 +115,7 @@ describe("neurons-table.utils", () => { domKey: "42", neuronId: "42", stake: makeStake(stake1), + stakeInUsd: makeUsdStake(stake1), }, { ...defaultExpectedTableNeuron, @@ -112,6 +123,7 @@ describe("neurons-table.utils", () => { domKey: "342", neuronId: "342", stake: makeStake(stake2), + stakeInUsd: makeUsdStake(stake2), }, ]); }); @@ -131,6 +143,7 @@ describe("neurons-table.utils", () => { { ...defaultExpectedTableNeuron, stake: makeStake(stake), + stakeInUsd: makeUsdStake(stake), }, ]); }); @@ -190,6 +203,7 @@ describe("neurons-table.utils", () => { ...defaultExpectedTableNeuron, rowHref: undefined, stake: makeStake(0n), + stakeInUsd: 0, state: NeuronState.Spawning, }, ]); @@ -226,6 +240,9 @@ describe("neurons-table.utils", () => { neuronInfos: [hotkeyNeuronInfo], identity: mockIdentity, accounts: mockAccountsStoreData, + icpSwapUsdPrices: { + [LEDGER_CANISTER_ID.toText()]: icpPrice, + }, i18n: en, }); expect(tableNeurons).toEqual([ @@ -239,10 +256,12 @@ describe("neurons-table.utils", () => { describe("tableNeuronsFromSnsNeurons", () => { const snsUniverseIdText = "br5f7-7uaaa-aaaaa-qaaca-cai"; + const ledgerCanisterId = Principal.fromText("wxkl4-qiqaa-2q"); const neuronIdString = "123456789abcdef0"; const neuronId = hexStringToBytes(neuronIdString); const stake = 300_000n; const dissolveDelaySeconds = 8640000n; + const snsTokenPrice = 0.25; const defaultCreateMockSnsNeuronParams = { id: neuronId, @@ -261,11 +280,15 @@ describe("neurons-table.utils", () => { token: mockSnsToken, }); + const makeSnsUsdStake = (amount: bigint) => + (Number(amount) * snsTokenPrice) / 100_000_000; + const expectedTableNeuron = { rowHref: "/neuron/?u=br5f7-7uaaa-aaaaa-qaaca-cai&neuron=123456789abcdef0", domKey: neuronIdString, neuronId: neuronIdString, stake: makeSnsStake(stake), + stakeInUsd: makeSnsUsdStake(stake), availableMaturity: 0n, stakedMaturity: 0n, dissolveDelaySeconds, @@ -280,6 +303,10 @@ describe("neurons-table.utils", () => { universe: snsUniverseIdText, token: mockSnsToken, identity: mockIdentity, + icpSwapUsdPrices: { + [ledgerCanisterId.toText()]: snsTokenPrice, + }, + ledgerCanisterId, i18n: en, }); diff --git a/frontend/src/tests/mocks/icp-transactions.mock.ts b/frontend/src/tests/mocks/icp-transactions.mock.ts index a36627efe94..6fad5a6dc40 100644 --- a/frontend/src/tests/mocks/icp-transactions.mock.ts +++ b/frontend/src/tests/mocks/icp-transactions.mock.ts @@ -22,6 +22,10 @@ export const mockTransactionTransfer: Transaction = { timestamp: [{ timestamp_nanos: 235n }], }; +export const dateToNanoSeconds = (date: Date): bigint => { + return BigInt(date.getTime()) * BigInt(NANO_SECONDS_IN_MILLISECOND); +}; + const defaultTimestamp = new Date("2023-01-01T00:00:00.000Z"); export const createTransactionWithId = ({ memo, @@ -35,8 +39,7 @@ export const createTransactionWithId = ({ id?: bigint; }): TransactionWithId => { const timestampNanos = { - timestamp_nanos: - BigInt(timestamp.getTime()) * BigInt(NANO_SECONDS_IN_MILLISECOND), + timestamp_nanos: dateToNanoSeconds(timestamp), }; return { id, diff --git a/frontend/src/tests/mocks/neurons.mock.ts b/frontend/src/tests/mocks/neurons.mock.ts index 4e04e5a4aaf..dbec2dead4a 100644 --- a/frontend/src/tests/mocks/neurons.mock.ts +++ b/frontend/src/tests/mocks/neurons.mock.ts @@ -115,6 +115,7 @@ export const mockTableNeuron: TableNeuron = { amount: 1n, token: ICPToken, }), + stakeInUsd: 10, availableMaturity: 0n, stakedMaturity: 0n, dissolveDelaySeconds: 1n, diff --git a/frontend/src/tests/page-objects/NeuronStakeCell.page-object.ts b/frontend/src/tests/page-objects/NeuronStakeCell.page-object.ts index 9aa98776f8b..25ec5177650 100644 --- a/frontend/src/tests/page-objects/NeuronStakeCell.page-object.ts +++ b/frontend/src/tests/page-objects/NeuronStakeCell.page-object.ts @@ -1,4 +1,5 @@ import { AmountDisplayPo } from "$tests/page-objects/AmountDisplay.page-object"; +import { AmountWithUsdPo } from "$tests/page-objects/AmountWithUsd.page-object"; import { BasePageObject } from "$tests/page-objects/base.page-object"; import type { PageObjectElement } from "$tests/types/page-object.types"; @@ -9,6 +10,10 @@ export class NeuronStakeCellPo extends BasePageObject { return new NeuronStakeCellPo(element.byTestId(NeuronStakeCellPo.TID)); } + getAmountWithUsdPo(): AmountWithUsdPo { + return AmountWithUsdPo.under(this.root); + } + getAmountDisplayPo(): AmountDisplayPo { return AmountDisplayPo.under(this.root); } @@ -20,4 +25,12 @@ export class NeuronStakeCellPo extends BasePageObject { getStakeBalance(): Promise { return this.getAmountDisplayPo().getAmount(); } + + async getStakeInUsd(): Promise { + return await this.getAmountWithUsdPo().getAmountInUsd(); + } + + async hasStakeInUsd(): Promise { + return await this.getAmountWithUsdPo().isPresent(); + } } diff --git a/frontend/src/tests/page-objects/NeuronsTableRow.page-object.ts b/frontend/src/tests/page-objects/NeuronsTableRow.page-object.ts index 3f9302a5c65..d077bace992 100644 --- a/frontend/src/tests/page-objects/NeuronsTableRow.page-object.ts +++ b/frontend/src/tests/page-objects/NeuronsTableRow.page-object.ts @@ -46,6 +46,14 @@ export class NeuronsTableRowPo extends ResponsiveTableRowPo { return this.getNeuronStakeCellPo().getStake(); } + getStakeInUsd(): Promise { + return this.getNeuronStakeCellPo().getStakeInUsd(); + } + + hasStakeInUsd(): Promise { + return this.getNeuronStakeCellPo().hasStakeInUsd(); + } + // Stake without the currency symbol getStakeBalance(): Promise { return this.getNeuronStakeCellPo().getStakeBalance(); diff --git a/frontend/src/tests/page-objects/NnsNeuronVotingPowerSection.page-object.ts b/frontend/src/tests/page-objects/NnsNeuronVotingPowerSection.page-object.ts index 86102a10af8..ea0839209ed 100644 --- a/frontend/src/tests/page-objects/NnsNeuronVotingPowerSection.page-object.ts +++ b/frontend/src/tests/page-objects/NnsNeuronVotingPowerSection.page-object.ts @@ -18,6 +18,10 @@ export class NnsNeuronVotingPowerSectionPo extends BasePageObject { return this.getText("voting-power"); } + getGenericDescription(): Promise { + return this.getText("voting-power-generic-description"); + } + getDescription(): Promise { return this.getText("voting-power-description"); } diff --git a/frontend/src/tests/page-objects/ReportingDateRangeSelector.page-object.ts b/frontend/src/tests/page-objects/ReportingDateRangeSelector.page-object.ts new file mode 100644 index 00000000000..16a121e2dbb --- /dev/null +++ b/frontend/src/tests/page-objects/ReportingDateRangeSelector.page-object.ts @@ -0,0 +1,24 @@ +import type { PageObjectElement } from "$tests/types/page-object.types"; +import { SimpleBasePageObject } from "./simple-base.page-object"; + +export class ReportingDateRangeSelectorPo extends SimpleBasePageObject { + static readonly TID = "reporting-data-range-selector-component"; + + static under({ + element, + }: { + element: PageObjectElement; + }): ReportingDateRangeSelectorPo { + return new ReportingDateRangeSelectorPo( + element.byTestId(ReportingDateRangeSelectorPo.TID) + ); + } + + getAllOptions() { + return this.getElement().querySelectorAll('input[type="radio"]'); + } + + getSelectedOption() { + return this.getElement().querySelector('input[type="radio"]:checked'); + } +}