From bc68df8fe87c310f406663a73444f918d272422b Mon Sep 17 00:00:00 2001 From: Maxime Beauchamp <15185355+baktun14@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:01:11 -0400 Subject: [PATCH 01/11] feat(console): add metamask (#334) --- apps/deploy-web/package.json | 1 + .../src/components/layout/WalletStatus.tsx | 10 +- .../components/settings/CertificateList.tsx | 4 +- .../CertificateProviderContext.tsx | 2 +- .../CustomChainProvider.tsx | 3 +- package-lock.json | 341 +++++++++++++----- packages/dev-config/.eslintrc.base.js | 2 +- packages/ui/components/custom/address.tsx | 2 +- 8 files changed, 258 insertions(+), 107 deletions(-) diff --git a/apps/deploy-web/package.json b/apps/deploy-web/package.json index c48a2f906..28465d876 100644 --- a/apps/deploy-web/package.json +++ b/apps/deploy-web/package.json @@ -26,6 +26,7 @@ "@cosmjs/encoding": "^0.32.4", "@cosmjs/proto-signing": "^0.32.4", "@cosmjs/stargate": "^0.32.4", + "@cosmos-kit/cosmos-extension-metamask": "0.10.0", "@cosmos-kit/cosmostation-extension": "^2.12.2", "@cosmos-kit/keplr": "^2.12.2", "@cosmos-kit/leap": "^2.12.2", diff --git a/apps/deploy-web/src/components/layout/WalletStatus.tsx b/apps/deploy-web/src/components/layout/WalletStatus.tsx index f25c0b2f1..d62748973 100644 --- a/apps/deploy-web/src/components/layout/WalletStatus.tsx +++ b/apps/deploy-web/src/components/layout/WalletStatus.tsx @@ -23,6 +23,7 @@ import { browserEnvConfig } from "@src/config/browser-env.config"; import { useWallet } from "@src/context/WalletProvider"; import { useLoginRequiredEventHandler } from "@src/hooks/useLoginRequiredEventHandler"; import { useManagedEscrowFaqModal } from "@src/hooks/useManagedEscrowFaqModal"; +import { getSplitText } from "@src/hooks/useShortText"; import { useWalletBalance } from "@src/hooks/useWalletBalance"; import { udenomToDenom } from "@src/utils/mathHelpers"; import { uaktToAKT } from "@src/utils/priceUtils"; @@ -104,10 +105,15 @@ export function WalletStatus() { - {walletName} + {walletName?.length > 20 ? ( + {getSplitText(walletName, 4, 4)} + ) : ( + {walletName} + )} -
+
{walletName}
+
diff --git a/apps/deploy-web/src/components/settings/CertificateList.tsx b/apps/deploy-web/src/components/settings/CertificateList.tsx index 10cd555b2..cb4259960 100644 --- a/apps/deploy-web/src/components/settings/CertificateList.tsx +++ b/apps/deploy-web/src/components/settings/CertificateList.tsx @@ -1,7 +1,7 @@ "use client"; -import { useState, useEffect } from "react"; +import { useEffect,useState } from "react"; import { FormattedDate } from "react-intl"; -import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, CustomPagination } from "@akashnetwork/ui/components"; +import { Button, CustomPagination,Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@akashnetwork/ui/components"; import { Check } from "iconoir-react"; import { ConnectWallet } from "@src/components/shared/ConnectWallet"; diff --git a/apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx b/apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx index deddee560..1bdc6a47e 100644 --- a/apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx +++ b/apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx @@ -7,11 +7,11 @@ import { useSnackbar } from "notistack"; import { RestApiCertificate } from "@src/types/certificate"; import { AnalyticsEvents } from "@src/utils/analytics"; +import { ApiUrlService, loadWithPagination } from "@src/utils/apiUtils"; import { TransactionMessageData } from "@src/utils/TransactionMessageData"; import { getStorageWallets, updateWallet } from "@src/utils/walletUtils"; import { useSettings } from "../SettingsProvider"; import { useWallet } from "../WalletProvider"; -import { ApiUrlService, loadWithPagination } from "@src/utils/apiUtils"; export type LocalCert = { certPem: string; diff --git a/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx b/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx index 4586935aa..35e3f207d 100644 --- a/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx +++ b/apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx @@ -3,6 +3,7 @@ import "@interchain-ui/react/styles"; import "@interchain-ui/react/globalStyles"; import { GasPrice } from "@cosmjs/stargate"; +import { wallets as metamask } from "@cosmos-kit/cosmos-extension-metamask"; import { wallets as cosmostation } from "@cosmos-kit/cosmostation-extension"; import { wallets as keplr } from "@cosmos-kit/keplr"; import { wallets as leap } from "@cosmos-kit/leap"; @@ -22,7 +23,7 @@ export function CustomChainProvider({ children }: Props) { { diff --git a/package-lock.json b/package-lock.json index 7bf578f30..e5ab20bb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -277,6 +277,7 @@ "@cosmjs/encoding": "^0.32.4", "@cosmjs/proto-signing": "^0.32.4", "@cosmjs/stargate": "^0.32.4", + "@cosmos-kit/cosmos-extension-metamask": "0.10.0", "@cosmos-kit/cosmostation-extension": "^2.12.2", "@cosmos-kit/keplr": "^2.12.2", "@cosmos-kit/leap": "^2.12.2", @@ -2827,20 +2828,22 @@ "integrity": "sha512-HPyeRCroJo04xJVHPvT05eskXn4EbII7LyJBsP2ol5jr0wseBBj94ISheB/Xr/moLY5PjZWW4G0foSD+4RiWsA==" }, "node_modules/@chain-registry/keplr": { - "version": "1.68.71", - "resolved": "https://registry.npmjs.org/@chain-registry/keplr/-/keplr-1.68.71.tgz", - "integrity": "sha512-QLRDj3thHh0FNCI42gZa2v1EAn/d7TqdhCc2TcoFQinz/Ziwym7tC++vzsQr+zAruEwMXru6vSGM7owgJIDBmg==", + "version": "1.68.2", + "resolved": "https://registry.npmjs.org/@chain-registry/keplr/-/keplr-1.68.2.tgz", + "integrity": "sha512-H3rdf/cLx7bNyyKo+1nI9HpLTlLzyeqi0Rmt+ggwtFRC63ZmDaMg/3vPY4rHvu38OdcaOid4Nyfc+7h3EEPW8Q==", + "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@chain-registry/types": "^0.45.57", + "@chain-registry/types": "^0.45.1", "@keplr-wallet/cosmos": "0.12.28", "@keplr-wallet/crypto": "0.12.28", "semver": "^7.5.0" } }, "node_modules/@chain-registry/keplr/node_modules/@chain-registry/types": { - "version": "0.45.57", - "resolved": "https://registry.npmjs.org/@chain-registry/types/-/types-0.45.57.tgz", - "integrity": "sha512-HPyeRCroJo04xJVHPvT05eskXn4EbII7LyJBsP2ol5jr0wseBBj94ISheB/Xr/moLY5PjZWW4G0foSD+4RiWsA==" + "version": "0.45.55", + "resolved": "https://registry.npmjs.org/@chain-registry/types/-/types-0.45.55.tgz", + "integrity": "sha512-uy7DQzLgxLOoVL5EyNUUUvftcoJznij06sXVUavdO/4w8HPFTpuAibY9aB7u/ILpIvirQsa6czMRIuWkRQdHEw==", + "license": "SEE LICENSE IN LICENSE" }, "node_modules/@chain-registry/types": { "version": "0.41.4", @@ -4130,6 +4133,22 @@ "xstream": "^11.14.0" } }, + "node_modules/@cosmos-kit/cosmos-extension-metamask": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@cosmos-kit/cosmos-extension-metamask/-/cosmos-extension-metamask-0.10.0.tgz", + "integrity": "sha512-Ii+1MnVDXECjlLH3djer0GORa/R23dgv6fyKPiXhoE0tynzLTlWcwC4OGHZUxgQIpRdTATshivuZEGVvdV+ctA==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@chain-registry/keplr": "1.68.2", + "@cosmos-kit/core": "^2.13.1", + "@cosmsnap/snapper": "^0.2.5", + "cosmjs-types": ">=0.9.0" + }, + "peerDependencies": { + "@cosmjs/amino": ">=0.32.3", + "@cosmjs/proto-signing": ">=0.32.3" + } + }, "node_modules/@cosmos-kit/cosmostation-extension": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/@cosmos-kit/cosmostation-extension/-/cosmostation-extension-2.13.0.tgz", @@ -4198,22 +4217,6 @@ "@cosmjs/proto-signing": ">=0.32.3" } }, - "node_modules/@cosmos-kit/keplr-mobile/node_modules/@chain-registry/keplr": { - "version": "1.68.2", - "resolved": "https://registry.npmjs.org/@chain-registry/keplr/-/keplr-1.68.2.tgz", - "integrity": "sha512-H3rdf/cLx7bNyyKo+1nI9HpLTlLzyeqi0Rmt+ggwtFRC63ZmDaMg/3vPY4rHvu38OdcaOid4Nyfc+7h3EEPW8Q==", - "dependencies": { - "@chain-registry/types": "^0.45.1", - "@keplr-wallet/cosmos": "0.12.28", - "@keplr-wallet/crypto": "0.12.28", - "semver": "^7.5.0" - } - }, - "node_modules/@cosmos-kit/keplr-mobile/node_modules/@chain-registry/types": { - "version": "0.45.57", - "resolved": "https://registry.npmjs.org/@chain-registry/types/-/types-0.45.57.tgz", - "integrity": "sha512-HPyeRCroJo04xJVHPvT05eskXn4EbII7LyJBsP2ol5jr0wseBBj94ISheB/Xr/moLY5PjZWW4G0foSD+4RiWsA==" - }, "node_modules/@cosmos-kit/leap": { "version": "2.12.2", "resolved": "https://registry.npmjs.org/@cosmos-kit/leap/-/leap-2.12.2.tgz", @@ -4238,22 +4241,6 @@ "@cosmjs/proto-signing": ">=0.32.3" } }, - "node_modules/@cosmos-kit/leap-extension/node_modules/@chain-registry/keplr": { - "version": "1.68.2", - "resolved": "https://registry.npmjs.org/@chain-registry/keplr/-/keplr-1.68.2.tgz", - "integrity": "sha512-H3rdf/cLx7bNyyKo+1nI9HpLTlLzyeqi0Rmt+ggwtFRC63ZmDaMg/3vPY4rHvu38OdcaOid4Nyfc+7h3EEPW8Q==", - "dependencies": { - "@chain-registry/types": "^0.45.1", - "@keplr-wallet/cosmos": "0.12.28", - "@keplr-wallet/crypto": "0.12.28", - "semver": "^7.5.0" - } - }, - "node_modules/@cosmos-kit/leap-extension/node_modules/@chain-registry/types": { - "version": "0.45.57", - "resolved": "https://registry.npmjs.org/@chain-registry/types/-/types-0.45.57.tgz", - "integrity": "sha512-HPyeRCroJo04xJVHPvT05eskXn4EbII7LyJBsP2ol5jr0wseBBj94ISheB/Xr/moLY5PjZWW4G0foSD+4RiWsA==" - }, "node_modules/@cosmos-kit/leap-metamask-cosmos-snap": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@cosmos-kit/leap-metamask-cosmos-snap/-/leap-metamask-cosmos-snap-0.12.2.tgz", @@ -4271,46 +4258,6 @@ "cosmjs-types": ">=0.9.0" } }, - "node_modules/@cosmos-kit/leap-metamask-cosmos-snap/node_modules/@chain-registry/keplr": { - "version": "1.68.2", - "resolved": "https://registry.npmjs.org/@chain-registry/keplr/-/keplr-1.68.2.tgz", - "integrity": "sha512-H3rdf/cLx7bNyyKo+1nI9HpLTlLzyeqi0Rmt+ggwtFRC63ZmDaMg/3vPY4rHvu38OdcaOid4Nyfc+7h3EEPW8Q==", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@chain-registry/types": "^0.45.1", - "@keplr-wallet/cosmos": "0.12.28", - "@keplr-wallet/crypto": "0.12.28", - "semver": "^7.5.0" - } - }, - "node_modules/@cosmos-kit/leap-metamask-cosmos-snap/node_modules/@chain-registry/types": { - "version": "0.45.61", - "resolved": "https://registry.npmjs.org/@chain-registry/types/-/types-0.45.61.tgz", - "integrity": "sha512-ScSUGG+0FJ+hI19c344ixDRdxdYr5YtU6zCY5Jhb/CJiPxjuoIv2US7a9qBysKGdIYK7iNrp8K5IoSGTRusKfg==", - "license": "SEE LICENSE IN LICENSE" - }, - "node_modules/@cosmos-kit/leap-metamask-cosmos-snap/node_modules/@metamask/providers": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-11.1.2.tgz", - "integrity": "sha512-xjE4cKrGpKZjripkMKMStc0H4LXrWJPijfbaj1kKeDLVhRH2Yu3ZecV3iIhf1EIJePeA+Kx6Pcm7d0IVJ+ea7g==", - "license": "MIT", - "dependencies": { - "@metamask/object-multiplex": "^1.1.0", - "@metamask/safe-event-emitter": "^3.0.0", - "detect-browser": "^5.2.0", - "eth-rpc-errors": "^4.0.2", - "extension-port-stream": "^2.1.1", - "fast-deep-equal": "^3.1.3", - "is-stream": "^2.0.0", - "json-rpc-engine": "^6.1.0", - "json-rpc-middleware-stream": "^4.2.1", - "pump": "^3.0.0", - "webextension-polyfill": "^0.10.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/@cosmos-kit/leap-mobile": { "version": "2.11.2", "resolved": "https://registry.npmjs.org/@cosmos-kit/leap-mobile/-/leap-mobile-2.11.2.tgz", @@ -4322,24 +4269,6 @@ "@cosmos-kit/walletconnect": "^2.10.1" } }, - "node_modules/@cosmos-kit/leap-mobile/node_modules/@chain-registry/keplr": { - "version": "1.68.2", - "resolved": "https://registry.npmjs.org/@chain-registry/keplr/-/keplr-1.68.2.tgz", - "integrity": "sha512-H3rdf/cLx7bNyyKo+1nI9HpLTlLzyeqi0Rmt+ggwtFRC63ZmDaMg/3vPY4rHvu38OdcaOid4Nyfc+7h3EEPW8Q==", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@chain-registry/types": "^0.45.1", - "@keplr-wallet/cosmos": "0.12.28", - "@keplr-wallet/crypto": "0.12.28", - "semver": "^7.5.0" - } - }, - "node_modules/@cosmos-kit/leap-mobile/node_modules/@chain-registry/types": { - "version": "0.45.61", - "resolved": "https://registry.npmjs.org/@chain-registry/types/-/types-0.45.61.tgz", - "integrity": "sha512-ScSUGG+0FJ+hI19c344ixDRdxdYr5YtU6zCY5Jhb/CJiPxjuoIv2US7a9qBysKGdIYK7iNrp8K5IoSGTRusKfg==", - "license": "SEE LICENSE IN LICENSE" - }, "node_modules/@cosmos-kit/react": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/@cosmos-kit/react/-/react-2.18.0.tgz", @@ -4405,6 +4334,92 @@ "resolved": "https://registry.npmjs.org/@cosmostation/extension-client/-/extension-client-0.1.15.tgz", "integrity": "sha512-HlXYJjFrNpjiV/GUKhri1UL8/bhlOIFFLpRF78YDSqq16x0+plIqx5CAvEusFcKTDpVfpeD5sfUHiKvP7euNFg==" }, + "node_modules/@cosmsnap/snapper": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@cosmsnap/snapper/-/snapper-0.2.7.tgz", + "integrity": "sha512-APdNxu6b761pNL9LTk4uxQr+cE88TdW6abtkVKxOgJcOtRsheI5mj7d5/hcIsm1dSiHv6WXefYdcTG9sOU/K9A==", + "license": "MIT", + "dependencies": { + "@cosmjs/amino": "^0.31.3", + "@keplr-wallet/proto-types": "0.12.12", + "@keplr-wallet/types": "0.12.12", + "appwrite": "^14.0.0", + "node-appwrite": "^14.0.0", + "ses": "^0.18.4" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@cosmsnap/snapper/node_modules/@cosmjs/amino": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.3.tgz", + "integrity": "sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3" + } + }, + "node_modules/@cosmsnap/snapper/node_modules/@cosmjs/crypto": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.3.tgz", + "integrity": "sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==", + "license": "Apache-2.0", + "dependencies": { + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers-sumo": "^0.7.11" + } + }, + "node_modules/@cosmsnap/snapper/node_modules/@cosmjs/encoding": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.3.tgz", + "integrity": "sha512-6IRtG0fiVYwyP7n+8e54uTx2pLYijO48V3t9TLiROERm5aUAIzIlz6Wp0NYaI5he9nh1lcEGJ1lkquVKFw3sUg==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "bech32": "^1.1.4", + "readonly-date": "^1.0.0" + } + }, + "node_modules/@cosmsnap/snapper/node_modules/@cosmjs/math": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.3.tgz", + "integrity": "sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0" + } + }, + "node_modules/@cosmsnap/snapper/node_modules/@cosmjs/utils": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.3.tgz", + "integrity": "sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==", + "license": "Apache-2.0" + }, + "node_modules/@cosmsnap/snapper/node_modules/@keplr-wallet/proto-types": { + "version": "0.12.12", + "resolved": "https://registry.npmjs.org/@keplr-wallet/proto-types/-/proto-types-0.12.12.tgz", + "integrity": "sha512-iAqqNlJpxu/8j+SwOXEH2ymM4W0anfxn+eNeWuqz2c/0JxGTWeLURioxQmCtewtllfHdDHHcoQ7/S+NmXiaEgQ==", + "license": "Apache-2.0", + "dependencies": { + "long": "^4.0.0", + "protobufjs": "^6.11.2" + } + }, + "node_modules/@cosmsnap/snapper/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "license": "Apache-2.0" + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "license": "MIT", @@ -6537,6 +6552,21 @@ "resolved": "https://registry.npmjs.org/@keplr-wallet/simple-fetch/-/simple-fetch-0.12.28.tgz", "integrity": "sha512-T2CiKS2B5n0ZA7CWw0CA6qIAH0XYI1siE50MP+i+V0ZniCGBeL+BMcDw64vFJUcEH+1L5X4sDAzV37fQxGwllA==" }, + "node_modules/@keplr-wallet/types": { + "version": "0.12.12", + "resolved": "https://registry.npmjs.org/@keplr-wallet/types/-/types-0.12.12.tgz", + "integrity": "sha512-fo6b8j9EXnJukGvZorifJWEm1BPIrvaTLuu5PqaU5k1ANDasm/FL1NaUuaTBVvhRjINtvVXqYpW/rVUinA9MBA==", + "license": "Apache-2.0", + "dependencies": { + "long": "^4.0.0" + } + }, + "node_modules/@keplr-wallet/types/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "license": "Apache-2.0" + }, "node_modules/@keplr-wallet/unit": { "version": "0.12.28", "resolved": "https://registry.npmjs.org/@keplr-wallet/unit/-/unit-0.12.28.tgz", @@ -6646,6 +6676,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-1.3.0.tgz", "integrity": "sha512-czcQeVYdSNtabd+NcYQnrM69MciiJyd1qvKH8WM2Id3C0ZiUUX5Xa/MK+/VUk633DBhVOwdNzAKIQ33lGyA+eQ==", + "license": "ISC", "dependencies": { "end-of-stream": "^1.4.4", "once": "^1.4.0", @@ -6655,10 +6686,33 @@ "node": ">=12.0.0" } }, + "node_modules/@metamask/providers": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-11.1.2.tgz", + "integrity": "sha512-xjE4cKrGpKZjripkMKMStc0H4LXrWJPijfbaj1kKeDLVhRH2Yu3ZecV3iIhf1EIJePeA+Kx6Pcm7d0IVJ+ea7g==", + "license": "MIT", + "dependencies": { + "@metamask/object-multiplex": "^1.1.0", + "@metamask/safe-event-emitter": "^3.0.0", + "detect-browser": "^5.2.0", + "eth-rpc-errors": "^4.0.2", + "extension-port-stream": "^2.1.1", + "fast-deep-equal": "^3.1.3", + "is-stream": "^2.0.0", + "json-rpc-engine": "^6.1.0", + "json-rpc-middleware-stream": "^4.2.1", + "pump": "^3.0.0", + "webextension-polyfill": "^0.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@metamask/safe-event-emitter": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.1.tgz", "integrity": "sha512-ihb3B0T/wJm1eUuArYP4lCTSEoZsClHhuWyfo/kMX3m/odpqNcPfsz5O2A3NT7dXCAgWPGDQGPqygCpgeniKMw==", + "license": "ISC", "engines": { "node": ">=12.0.0" } @@ -15331,6 +15385,45 @@ "node": ">= 8" } }, + "node_modules/appwrite": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/appwrite/-/appwrite-14.0.1.tgz", + "integrity": "sha512-ORlvfqVif/2K3qKGgGiGfMP33Zwm+xxB1fIC4Lm3sojOkDd8u8YvgKQO0Meq5UXb8Dc0Rl66Z7qlGBAfRQ04bA==", + "license": "BSD-3-Clause", + "dependencies": { + "cross-fetch": "3.1.5", + "isomorphic-form-data": "2.0.0" + } + }, + "node_modules/appwrite/node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "license": "MIT", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/appwrite/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/arg": { "version": "5.0.2", "license": "MIT" @@ -19904,6 +19997,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", + "license": "MIT", "dependencies": { "fast-safe-stringify": "^2.0.6" } @@ -20133,6 +20227,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-2.1.1.tgz", "integrity": "sha512-qknp5o5rj2J9CRKfVB8KJr+uXQlrojNZzdESUPhKYLXf97TPcGf6qWWKmpsNNtUyOdzFhab1ON0jzouNxHHvow==", + "license": "ISC", "dependencies": { "webextension-polyfill": ">=0.10.0 <1.0" }, @@ -22705,6 +22800,29 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz", + "integrity": "sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==", + "license": "MIT", + "dependencies": { + "form-data": "^2.3.2" + } + }, + "node_modules/isomorphic-form-data/node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/isomorphic-ws": { "version": "4.0.1", "license": "MIT", @@ -24719,6 +24837,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", + "license": "ISC", "dependencies": { "@metamask/safe-event-emitter": "^2.0.0", "eth-rpc-errors": "^4.0.2" @@ -24730,12 +24849,14 @@ "node_modules/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", - "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==" + "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", + "license": "ISC" }, "node_modules/json-rpc-middleware-stream": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/json-rpc-middleware-stream/-/json-rpc-middleware-stream-4.2.3.tgz", "integrity": "sha512-4iFb0yffm5vo3eFKDbQgke9o17XBcLQ2c3sONrXSbcOLzP8LTojqo8hRGVgtJShhm5q4ZDSNq039fAx9o65E1w==", + "license": "ISC", "dependencies": { "@metamask/safe-event-emitter": "^3.0.0", "json-rpc-engine": "^6.1.0", @@ -28228,6 +28349,15 @@ "version": "4.3.0", "license": "MIT" }, + "node_modules/node-appwrite": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-14.1.0.tgz", + "integrity": "sha512-kuKAZrdaAcGYOMUXtxNb1j+uIy+FIMiiU1dFkgwTXLsMLeLvC6HJ8/FH/kN9JyrWR2a2zcGN7gWfyQgWYoLMTA==", + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-native-with-agent": "1.7.2" + } + }, "node_modules/node-dependency-injection": { "version": "3.1.2", "license": "MIT", @@ -28419,6 +28549,12 @@ "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==" }, + "node_modules/node-fetch-native-with-agent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz", + "integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==", + "license": "MIT" + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -32053,6 +32189,12 @@ "node": ">= 0.8.0" } }, + "node_modules/ses": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/ses/-/ses-0.18.4.tgz", + "integrity": "sha512-Ph0PC38Q7uutHmMM9XPqA7rp/2taiRwW6pIZJwTr4gz90DtrBvy/x7AmNPH2uqNPhKriZpYKvPi1xKWjM9xJuQ==", + "license": "Apache-2.0" + }, "node_modules/set-blocking": { "version": "2.0.0", "license": "ISC" @@ -35191,7 +35333,8 @@ "node_modules/webextension-polyfill": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", + "license": "MPL-2.0" }, "node_modules/webidl-conversions": { "version": "3.0.1", diff --git a/packages/dev-config/.eslintrc.base.js b/packages/dev-config/.eslintrc.base.js index a8d461aa5..0b6ca3f6f 100644 --- a/packages/dev-config/.eslintrc.base.js +++ b/packages/dev-config/.eslintrc.base.js @@ -5,7 +5,7 @@ module.exports = { }, extends: ["eslint:recommended"], plugins: ["simple-import-sort"], - ignorePatterns: ["node_modules", "dist", "build", "public"], + ignorePatterns: ["node_modules", "dist", "build", "public", "Leap"], rules: { "@typescript-eslint/no-unused-vars": ["error", { ignoreRestSiblings: true }], "simple-import-sort/imports": [ diff --git a/packages/ui/components/custom/address.tsx b/packages/ui/components/custom/address.tsx index add9479f2..ae70ac7b5 100644 --- a/packages/ui/components/custom/address.tsx +++ b/packages/ui/components/custom/address.tsx @@ -43,7 +43,7 @@ export const Address: React.FunctionComponent = ({ address, isCopyable, d {...rest} > {formattedAddress} - {isCopyable && } + {isCopyable && } ); From 149c1b5abfd5dfcbaf6db714f5bdb05b23c9748c Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 11:16:52 +0200 Subject: [PATCH 02/11] feat(config): replace network ids constants with imports from network store refs #163, #313 --- .commitlintrc.json | 1 + apps/stats-web/package.json | 1 + .../src/components/layout/NetworkSelect.tsx | 9 ++++--- .../stats-web/src/hooks/useSelectedNetwork.ts | 6 ++--- apps/stats-web/src/lib/constants.ts | 26 +++++++++---------- apps/stats-web/src/store/networkStore.ts | 8 +++--- docker-compose.yml | 1 + 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/.commitlintrc.json b/.commitlintrc.json index cc3116586..08b772fed 100644 --- a/.commitlintrc.json +++ b/.commitlintrc.json @@ -15,6 +15,7 @@ "deployment", "certificate", "dx", + "config", "stats" ] ] diff --git a/apps/stats-web/package.json b/apps/stats-web/package.json index 6584bc329..bbeed2284 100644 --- a/apps/stats-web/package.json +++ b/apps/stats-web/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@akashnetwork/ui": "*", + "@akashnetwork/network-store": "*", "@cosmjs/encoding": "^0.32.4", "@json2csv/plainjs": "^7.0.4", "@nivo/line": "^0.87.0", diff --git a/apps/stats-web/src/components/layout/NetworkSelect.tsx b/apps/stats-web/src/components/layout/NetworkSelect.tsx index 9e81c351a..8f5b9bca0 100644 --- a/apps/stats-web/src/components/layout/NetworkSelect.tsx +++ b/apps/stats-web/src/components/layout/NetworkSelect.tsx @@ -1,8 +1,9 @@ "use client"; import React, { useEffect, useState } from "react"; +import { MAINNET_ID, Network } from "@akashnetwork/network-store"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Spinner } from "@akashnetwork/ui/components"; -import { mainnetId, setNetworkVersion } from "@/lib/constants"; +import { setNetworkVersion } from "@/lib/constants"; import { cn } from "@/lib/utils"; import { initiateNetworkData, networks } from "@/store/networkStore"; @@ -12,14 +13,14 @@ interface NetworkSelectProps { const NetworkSelect: React.FC = ({ className }) => { const [isLoadingSettings, setIsLoadingSettings] = useState(true); - const [selectedNetworkId, setSelectedNetworkId] = useState(mainnetId); + const [selectedNetworkId, setSelectedNetworkId] = useState(MAINNET_ID); useEffect(() => { async function init() { await initiateNetworkData(); setNetworkVersion(); - const selectedNetworkId = localStorage.getItem("selectedNetworkId"); + const selectedNetworkId = localStorage.getItem("selectedNetworkId") as Network["id"]; if (selectedNetworkId) { setSelectedNetworkId(selectedNetworkId); } @@ -30,7 +31,7 @@ const NetworkSelect: React.FC = ({ className }) => { init(); }, []); - const onSelectNetworkChange = (networkId: string) => { + const onSelectNetworkChange = (networkId: Network["id"]) => { setSelectedNetworkId(networkId); // Set in the settings and local storage diff --git a/apps/stats-web/src/hooks/useSelectedNetwork.ts b/apps/stats-web/src/hooks/useSelectedNetwork.ts index 44c1f4e42..83a65c86a 100644 --- a/apps/stats-web/src/hooks/useSelectedNetwork.ts +++ b/apps/stats-web/src/hooks/useSelectedNetwork.ts @@ -1,11 +1,11 @@ +import { MAINNET_ID } from "@akashnetwork/network-store"; import { useAtom } from "jotai"; import { useEffectOnce } from "usehooks-ts"; -import { mainnetId } from "@/lib/constants"; import networkStore, { networks } from "@/store/networkStore"; export const getSelectedNetwork = () => { - const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? mainnetId; + const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? MAINNET_ID; const selectedNetwork = networks.find(n => n.id === selectedNetworkId); // return mainnet if selected network is not found @@ -16,7 +16,7 @@ export const useSelectedNetwork = () => { const [selectedNetwork, setSelectedNetwork] = useAtom(networkStore.selectedNetwork); useEffectOnce(() => { - const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? mainnetId; + const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? MAINNET_ID; setSelectedNetwork(networks.find(n => n.id === selectedNetworkId) || networks[0]); }); diff --git a/apps/stats-web/src/lib/constants.ts b/apps/stats-web/src/lib/constants.ts index 3e2a46ed8..ca6ca930f 100644 --- a/apps/stats-web/src/lib/constants.ts +++ b/apps/stats-web/src/lib/constants.ts @@ -1,6 +1,4 @@ -export const mainnetId = "mainnet"; -export const testnetId = "testnet"; -export const sandboxId = "sandbox"; +import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; export const selectedRangeValues: { [key: string]: number } = { "7D": 7, @@ -23,9 +21,9 @@ export const BASE_API_URL = getApiUrl(); export function getNetworkBaseApiUrl(network: string | null) { switch (network) { - case testnetId: + case TESTNET_ID: return BASE_API_TESTNET_URL; - case sandboxId: + case SANDBOX_ID: return BASE_API_SANDBOX_URL; default: return BASE_API_MAINNET_URL; @@ -34,8 +32,8 @@ export function getNetworkBaseApiUrl(network: string | null) { export const uAktDenom = "uakt"; export const usdcIbcDenoms: { [key: string]: string } = { - [mainnetId]: "ibc/170C677610AC31DF0904FFE09CD3B5C657492170E7E52372E48756B71E56F2F1", - [sandboxId]: "ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84" + [MAINNET_ID]: "ibc/170C677610AC31DF0904FFE09CD3B5C657492170E7E52372E48756B71E56F2F1", + [SANDBOX_ID]: "ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84" }; function getApiMainnetUrl() { @@ -81,22 +79,22 @@ export function setNetworkVersion() { const _selectedNetworkId = localStorage.getItem("selectedNetworkId"); switch (_selectedNetworkId) { - case mainnetId: + case MAINNET_ID: networkVersion = "v1beta3"; - selectedNetworkId = mainnetId; + selectedNetworkId = MAINNET_ID; break; - case testnetId: + case TESTNET_ID: networkVersion = "v1beta3"; - selectedNetworkId = testnetId; + selectedNetworkId = TESTNET_ID; break; - case sandboxId: + case SANDBOX_ID: networkVersion = "v1beta3"; - selectedNetworkId = sandboxId; + selectedNetworkId = SANDBOX_ID; break; default: networkVersion = "v1beta3"; - selectedNetworkId = mainnetId; + selectedNetworkId = MAINNET_ID; break; } } diff --git a/apps/stats-web/src/store/networkStore.ts b/apps/stats-web/src/store/networkStore.ts index 7eba30159..9b02b4107 100644 --- a/apps/stats-web/src/store/networkStore.ts +++ b/apps/stats-web/src/store/networkStore.ts @@ -1,13 +1,13 @@ +import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; import axios from "axios"; import { atom } from "jotai"; import { ApiUrlService } from "@/lib/apiUtils"; -import { mainnetId, sandboxId, testnetId } from "@/lib/constants"; import { Network } from "@/types/network"; export let networks: Network[] = [ { - id: mainnetId, + id: MAINNET_ID, title: "Mainnet", description: "Akash Network mainnet network.", chainId: "akashnet-2", @@ -17,7 +17,7 @@ export let networks: Network[] = [ version: null // Set asynchronously }, { - id: testnetId, + id: TESTNET_ID, title: "GPU Testnet", description: "Testnet of the new GPU features.", chainId: "testnet-02", @@ -26,7 +26,7 @@ export let networks: Network[] = [ version: null // Set asynchronously }, { - id: sandboxId, + id: SANDBOX_ID, title: "Sandbox", description: "Sandbox of the mainnet version.", chainId: "sandbox-01", diff --git a/docker-compose.yml b/docker-compose.yml index e9f993d5e..73023682c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,3 +42,4 @@ services: - /app/node_modules - /app/apps/stats-web/node_modules - /app/apps/stats-web/.next + - ./packages:/app/packages From 0663a12a9e4eeb465dae8ed566c9ed86ac287725 Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 11:20:20 +0200 Subject: [PATCH 03/11] feat(config): extract date constants to a dedicated config refs #163, #313 --- .../app/graph/[snapshot]/GraphContainer.tsx | 6 +- .../[snapshot]/GraphContainer.tsx | 6 +- .../src/components/graph/TimeRange.tsx | 14 +- apps/stats-web/src/config/date.config.ts | 5 + apps/stats-web/src/lib/constants.ts | 6 - package-lock.json | 135 ++++++++++++++++++ 6 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 apps/stats-web/src/config/date.config.ts diff --git a/apps/stats-web/src/app/graph/[snapshot]/GraphContainer.tsx b/apps/stats-web/src/app/graph/[snapshot]/GraphContainer.tsx index bf73b139b..72e1c7ad0 100644 --- a/apps/stats-web/src/app/graph/[snapshot]/GraphContainer.tsx +++ b/apps/stats-web/src/app/graph/[snapshot]/GraphContainer.tsx @@ -9,7 +9,7 @@ import dynamic from "next/dynamic"; import { DiffNumber } from "@/components/DiffNumber"; import { DiffPercentageChip } from "@/components/DiffPercentageChip"; import { TimeRange } from "@/components/graph/TimeRange"; -import { selectedRangeValues } from "@/lib/constants"; +import { SELECTED_RANGE_VALUES } from "@/config/date.config"; import { percIncrease, udenomToDenom } from "@/lib/mathHelpers"; import { SNAPSHOT_NOT_FOUND } from "@/lib/snapshotsUrlHelpers"; import { bytesToShrink } from "@/lib/unitUtils"; @@ -25,7 +25,7 @@ export interface IGraphProps { } export default function GraphContainer({ snapshot }: IGraphProps) { - const [selectedRange, setSelectedRange] = useState(selectedRangeValues["7D"]); + const [selectedRange, setSelectedRange] = useState(SELECTED_RANGE_VALUES["7D"]); const { data: snapshotData, status } = useGraphSnapshot(snapshot); const snapshotMetadata = snapshotData && getSnapshotMetadata(snapshot as Snapshots); const rangedData = snapshotData && snapshotData.snapshots.slice(Math.max(snapshotData.snapshots.length - selectedRange, 0), snapshotData.snapshots.length); @@ -50,7 +50,7 @@ export default function GraphContainer({ snapshot }: IGraphProps) { const csvContent = parser.parse(rangedData.map(d => ({ date: d.date, value: snapshotMetadata.unitFn(d.value).value }))); const datePart = new Date().toISOString().substring(0, 10).replaceAll("-", ""); - const rangePart = Object.keys(selectedRangeValues).find(key => selectedRangeValues[key] === selectedRange); + const rangePart = Object.keys(SELECTED_RANGE_VALUES).find(key => SELECTED_RANGE_VALUES[key] === selectedRange); const fileName = `${snapshot}-${datePart}-${rangePart}.csv`; const encodedUri = encodeURI("data:text/csv;charset=utf-8," + csvContent); diff --git a/apps/stats-web/src/app/provider-graph/[snapshot]/GraphContainer.tsx b/apps/stats-web/src/app/provider-graph/[snapshot]/GraphContainer.tsx index ecec6a618..4d4234525 100644 --- a/apps/stats-web/src/app/provider-graph/[snapshot]/GraphContainer.tsx +++ b/apps/stats-web/src/app/provider-graph/[snapshot]/GraphContainer.tsx @@ -9,7 +9,7 @@ import dynamic from "next/dynamic"; import { DiffNumber } from "@/components/DiffNumber"; import { DiffPercentageChip } from "@/components/DiffPercentageChip"; import { TimeRange } from "@/components/graph/TimeRange"; -import { selectedRangeValues } from "@/lib/constants"; +import { SELECTED_RANGE_VALUES } from "@/config/date.config"; import { percIncrease } from "@/lib/mathHelpers"; import { getProviderSnapshotMetadata } from "@/lib/providerUtils"; import { SNAPSHOT_NOT_FOUND } from "@/lib/snapshotsUrlHelpers"; @@ -25,7 +25,7 @@ export interface IGraphProps { } export default function GraphContainer({ snapshot }: IGraphProps) { - const [selectedRange, setSelectedRange] = useState(selectedRangeValues["7D"]); + const [selectedRange, setSelectedRange] = useState(SELECTED_RANGE_VALUES["7D"]); const { data: snapshotData, status } = useProviderGraphSnapshot(snapshot); const snapshotMetadata = snapshotData && getProviderSnapshotMetadata(snapshot as ProviderSnapshots); const rangedData = snapshotData && snapshotData.snapshots.slice(Math.max(snapshotData.snapshots.length - selectedRange, 0), snapshotData.snapshots.length); @@ -50,7 +50,7 @@ export default function GraphContainer({ snapshot }: IGraphProps) { const csvContent = parser.parse(rangedData.map(d => ({ date: d.date, value: snapshotMetadata.unitFn(d.value).value }))); const datePart = new Date().toISOString().substring(0, 10).replaceAll("-", ""); - const rangePart = Object.keys(selectedRangeValues).find(key => selectedRangeValues[key] === selectedRange); + const rangePart = Object.keys(SELECTED_RANGE_VALUES).find(key => SELECTED_RANGE_VALUES[key] === selectedRange); const fileName = `${snapshot}-${datePart}-${rangePart}.csv`; const encodedUri = encodeURI("data:text/csv;charset=utf-8," + csvContent); diff --git a/apps/stats-web/src/components/graph/TimeRange.tsx b/apps/stats-web/src/components/graph/TimeRange.tsx index f1bd6ec76..aae2d5a4b 100644 --- a/apps/stats-web/src/components/graph/TimeRange.tsx +++ b/apps/stats-web/src/components/graph/TimeRange.tsx @@ -2,7 +2,7 @@ import { ReactNode } from "react"; import { ToggleGroup, ToggleGroupItem } from "@akashnetwork/ui/components"; -import { selectedRangeValues } from "@/lib/constants"; +import { SELECTED_RANGE_VALUES } from "@/config/date.config"; import { cn } from "@/lib/utils"; type Props = { @@ -20,24 +20,24 @@ export const TimeRange: React.FunctionComponent = ({ selectedRange, onRan _onRangeChange(selectedRangeValues["7D"])} + className={cn({ ["!bg-primary font-bold !text-white"]: selectedRange === SELECTED_RANGE_VALUES["7D"] })} + onClick={() => _onRangeChange(SELECTED_RANGE_VALUES["7D"])} size="sm" > 7D _onRangeChange(selectedRangeValues["1M"])} + className={cn({ ["!bg-primary font-bold !text-white"]: selectedRange === SELECTED_RANGE_VALUES["1M"] })} + onClick={() => _onRangeChange(SELECTED_RANGE_VALUES["1M"])} size="sm" > 1M _onRangeChange(selectedRangeValues["ALL"])} + className={cn({ ["!bg-primary font-bold !text-white"]: selectedRange === SELECTED_RANGE_VALUES["ALL"] })} + onClick={() => _onRangeChange(SELECTED_RANGE_VALUES["ALL"])} size="sm" > ALL diff --git a/apps/stats-web/src/config/date.config.ts b/apps/stats-web/src/config/date.config.ts new file mode 100644 index 000000000..de6acce2e --- /dev/null +++ b/apps/stats-web/src/config/date.config.ts @@ -0,0 +1,5 @@ +export const SELECTED_RANGE_VALUES: Record = { + "7D": 7, + "1M": 30, + ALL: Number.MAX_SAFE_INTEGER +}; diff --git a/apps/stats-web/src/lib/constants.ts b/apps/stats-web/src/lib/constants.ts index ca6ca930f..3c0974c6b 100644 --- a/apps/stats-web/src/lib/constants.ts +++ b/apps/stats-web/src/lib/constants.ts @@ -1,11 +1,5 @@ import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; -export const selectedRangeValues: { [key: string]: number } = { - "7D": 7, - "1M": 30, - ALL: Number.MAX_SAFE_INTEGER -}; - const productionMainnetApiUrl = "https://console-api.akash.network"; const productionTestnetApiUrl = "https://console-api-testnet.akash.network"; const productionSandboxApiUrl = "https://console-api-sandbox.akash.network"; diff --git a/package-lock.json b/package-lock.json index e5ab20bb3..ed7f9310f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36526,6 +36526,141 @@ "peerDependencies": { "react": ">=16.13.1" } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.6.tgz", + "integrity": "sha512-BtJZb+hYXGaVJJivpnDoi3JFVn80SHKCiiRUW3kk1SY6UCUy5dWFFSbh+tGi5lHAughzeduMyxbLt3pspvXNSg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.6.tgz", + "integrity": "sha512-ZHRbGpH6KHarzm6qEeXKSElSXh8dS2DtDPjQt3IMwY8QVk7GbdDYjvV4NgSnDA9huGpGgnyy3tH8i5yHCqVkiQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.6.tgz", + "integrity": "sha512-O4HqUEe3ZvKshXHcDUXn1OybN4cSZg7ZdwHJMGCXSUEVUqGTJVsOh17smqilIjooP/sIJksgl+1kcf2IWMZWHg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.6.tgz", + "integrity": "sha512-xUcdhr2hfalG8RDDGSFxQ75yOG894UlmFS4K2M0jLrUhauRBGOtUOxoDVwiIIuZQwZ3Y5hDsazNjdYGB0cQ9yQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.6.tgz", + "integrity": "sha512-InosKxw8UMcA/wEib5n2QttwHSKHZHNSbGcMepBM0CTcNwpxWzX32KETmwbhKod3zrS8n1vJ+DuJKbL9ZAB0Ag==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.6.tgz", + "integrity": "sha512-d4QXfJmt5pGJ7cG8qwxKSBnO5AXuKAFYxV7qyDRHnUNvY/dgDh+oX292gATpB2AAHgjdHd5ks1wXxIEj6muLUQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.6.tgz", + "integrity": "sha512-AlgIhk4/G+PzOG1qdF1b05uKTMsuRatFlFzAi5G8RZ9h67CVSSuZSbqGHbJDlcV1tZPxq/d4G0q6qcHDKWf4aQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.6.tgz", + "integrity": "sha512-hNukAxq7hu4o5/UjPp5jqoBEtrpCbOmnUqZSKNJG8GrUVzfq0ucdhQFVrHcLRMvQcwqqDh1a5AJN9ORnNDpgBQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.6.tgz", + "integrity": "sha512-NANtw+ead1rSDK1jxmzq3TYkl03UNK2KHqUYf1nIhNci6NkeqBD4s1njSzYGIlSHxCK+wSaL8RXZm4v+NF/pMw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } From c3e761e9fb4523f4527f86704d9bf238fafa4b2f Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 11:25:21 +0200 Subject: [PATCH 04/11] feat(config): extract denom constants to a dedicated config refs #163, #313 --- apps/stats-web/src/config/denom.config.ts | 8 ++++++++ .../PricingProvider/PricingProvider.tsx | 4 ++-- apps/stats-web/src/hooks/useDenom.ts | 20 +++---------------- apps/stats-web/src/lib/constants.ts | 6 ------ 4 files changed, 13 insertions(+), 25 deletions(-) create mode 100644 apps/stats-web/src/config/denom.config.ts diff --git a/apps/stats-web/src/config/denom.config.ts b/apps/stats-web/src/config/denom.config.ts new file mode 100644 index 000000000..eb079e6ba --- /dev/null +++ b/apps/stats-web/src/config/denom.config.ts @@ -0,0 +1,8 @@ +import type { MainnetNetworkId, SandboxNetworkId } from "@akashnetwork/akashjs/build/types/network"; +import { MAINNET_ID, SANDBOX_ID } from "@akashnetwork/network-store"; + +export const UAKT_DENOM = "uakt"; +export const USDC_IBC_DENOMS: Record = { + [MAINNET_ID]: "ibc/170C677610AC31DF0904FFE09CD3B5C657492170E7E52372E48756B71E56F2F1", + [SANDBOX_ID]: "ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84" +}; diff --git a/apps/stats-web/src/context/PricingProvider/PricingProvider.tsx b/apps/stats-web/src/context/PricingProvider/PricingProvider.tsx index bfc47ef9a..78347b0a3 100644 --- a/apps/stats-web/src/context/PricingProvider/PricingProvider.tsx +++ b/apps/stats-web/src/context/PricingProvider/PricingProvider.tsx @@ -2,8 +2,8 @@ import React from "react"; +import { UAKT_DENOM } from "@/config/denom.config"; import { useUsdcDenom } from "@/hooks/useDenom"; -import { uAktDenom } from "@/lib/constants"; import { roundDecimal } from "@/lib/mathHelpers"; import { useMarketData } from "@/queries"; @@ -42,7 +42,7 @@ export const PricingProvider: React.FC = ({ children }) => { const getPriceForDenom = (denom: string): number => { switch (denom) { - case uAktDenom: + case UAKT_DENOM: return marketData?.price || 0; case usdcIbcDenom: return 1; // TODO Get price from API diff --git a/apps/stats-web/src/hooks/useDenom.ts b/apps/stats-web/src/hooks/useDenom.ts index dde453160..3a2f76265 100644 --- a/apps/stats-web/src/hooks/useDenom.ts +++ b/apps/stats-web/src/hooks/useDenom.ts @@ -1,22 +1,8 @@ -import { getSelectedNetwork, useSelectedNetwork } from "./useSelectedNetwork"; +import { useSelectedNetwork } from "./useSelectedNetwork"; -import { usdcIbcDenoms } from "@/lib/constants"; +import { USDC_IBC_DENOMS } from "@/config/denom.config"; export const useUsdcDenom = () => { const selectedNetwork = useSelectedNetwork(); - return usdcIbcDenoms[selectedNetwork.id]; -}; - -export const getUsdcDenom = () => { - const selectedNetwork = getSelectedNetwork(); - return usdcIbcDenoms[selectedNetwork.id as any]; -}; - -export const useSdlDenoms = () => { - const usdcDenom = useUsdcDenom(); - - return [ - { id: "uakt", label: "uAKT", tokenLabel: "AKT", value: "uakt" }, - { id: "uusdc", label: "uUSDC", tokenLabel: "USDC", value: usdcDenom } - ]; + return USDC_IBC_DENOMS[selectedNetwork.id]; }; diff --git a/apps/stats-web/src/lib/constants.ts b/apps/stats-web/src/lib/constants.ts index 3c0974c6b..151c7e8c9 100644 --- a/apps/stats-web/src/lib/constants.ts +++ b/apps/stats-web/src/lib/constants.ts @@ -24,12 +24,6 @@ export function getNetworkBaseApiUrl(network: string | null) { } } -export const uAktDenom = "uakt"; -export const usdcIbcDenoms: { [key: string]: string } = { - [MAINNET_ID]: "ibc/170C677610AC31DF0904FFE09CD3B5C657492170E7E52372E48756B71E56F2F1", - [SANDBOX_ID]: "ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84" -}; - function getApiMainnetUrl() { if (process.env.API_MAINNET_BASE_URL) return process.env.API_MAINNET_BASE_URL; if (typeof window === "undefined") return "http://localhost:3080"; From 3d804d5b4f332dd702fb1be346c593bfb6c6ff71 Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 13:08:46 +0200 Subject: [PATCH 05/11] feat(config): replace network management with network store package Also add validated env configs to get essential network store vars refs #163, #313 --- apps/stats-web/.gitignore | 1 + apps/stats-web/env/.env.production | 1 + apps/stats-web/env/.env.sample | 1 + apps/stats-web/env/.env.staging | 1 + apps/stats-web/next.config.js | 11 +++ apps/stats-web/package.json | 3 +- .../src/app/(home)/DashboardContainer.tsx | 4 +- .../src/components/layout/CustomProviders.tsx | 3 +- .../src/components/layout/NetworkSelect.tsx | 40 ++--------- .../src/config/browser-env.config.ts | 6 ++ .../stats-web/src/config/env-config.schema.ts | 29 ++++++++ .../stats-web/src/config/server-env.config.ts | 5 ++ apps/stats-web/src/hooks/useDenom.ts | 7 +- .../stats-web/src/hooks/useSelectedNetwork.ts | 24 ------- apps/stats-web/src/lib/constants.ts | 34 ++-------- apps/stats-web/src/lib/urlUtils.ts | 28 ++------ apps/stats-web/src/store/global.store.ts | 3 + apps/stats-web/src/store/network.store.ts | 10 +++ apps/stats-web/src/store/networkStore.ts | 67 ------------------- packages/network-store/src/network.store.ts | 26 ++++++- 20 files changed, 116 insertions(+), 188 deletions(-) create mode 100644 apps/stats-web/env/.env.production create mode 100644 apps/stats-web/env/.env.sample create mode 100644 apps/stats-web/env/.env.staging create mode 100644 apps/stats-web/src/config/browser-env.config.ts create mode 100644 apps/stats-web/src/config/env-config.schema.ts create mode 100644 apps/stats-web/src/config/server-env.config.ts delete mode 100644 apps/stats-web/src/hooks/useSelectedNetwork.ts create mode 100644 apps/stats-web/src/store/global.store.ts create mode 100644 apps/stats-web/src/store/network.store.ts delete mode 100644 apps/stats-web/src/store/networkStore.ts diff --git a/apps/stats-web/.gitignore b/apps/stats-web/.gitignore index fd3dbb571..47fa2a149 100644 --- a/apps/stats-web/.gitignore +++ b/apps/stats-web/.gitignore @@ -15,6 +15,7 @@ # production /build +env-config.schema.js # misc .DS_Store diff --git a/apps/stats-web/env/.env.production b/apps/stats-web/env/.env.production new file mode 100644 index 000000000..dbd0c6496 --- /dev/null +++ b/apps/stats-web/env/.env.production @@ -0,0 +1 @@ +NEXT_PUBLIC_API_BASE_URL=https://console-api.akash.network \ No newline at end of file diff --git a/apps/stats-web/env/.env.sample b/apps/stats-web/env/.env.sample new file mode 100644 index 000000000..0e09e65e8 --- /dev/null +++ b/apps/stats-web/env/.env.sample @@ -0,0 +1 @@ +NEXT_PUBLIC_API_BASE_URL= \ No newline at end of file diff --git a/apps/stats-web/env/.env.staging b/apps/stats-web/env/.env.staging new file mode 100644 index 000000000..968b942c0 --- /dev/null +++ b/apps/stats-web/env/.env.staging @@ -0,0 +1 @@ +NEXT_PUBLIC_API_BASE_URL=https://console-api-mainnet-staging.akash.network \ No newline at end of file diff --git a/apps/stats-web/next.config.js b/apps/stats-web/next.config.js index 35ad76b7c..273c77080 100644 --- a/apps/stats-web/next.config.js +++ b/apps/stats-web/next.config.js @@ -1,5 +1,16 @@ +require("@akashnetwork/env-loader"); const { version } = require("./package.json"); +try { + const { browserEnvSchema } = require("./env-config.schema"); + + browserEnvSchema.parse(process.env); +} catch (error) { + if (error.message.includes("Cannot find module")) { + console.warn("No env-config.schema.js found, skipping env validation"); + } +} + /** @type {import('next').NextConfig} */ const nextConfig = { output: "standalone", diff --git a/apps/stats-web/package.json b/apps/stats-web/package.json index bbeed2284..7134d2993 100644 --- a/apps/stats-web/package.json +++ b/apps/stats-web/package.json @@ -3,7 +3,8 @@ "version": "0.20.0", "private": true, "scripts": { - "build": "next build", + "build": "npm run build-env-schemas && next build", + "build-env-schemas": "tsc src/config/env-config.schema.ts --outDir . --skipLibCheck", "dev": "next dev", "format": "prettier --write ./*.{ts,js,json} **/*.{ts,tsx,js,json}", "lint": "eslint .", diff --git a/apps/stats-web/src/app/(home)/DashboardContainer.tsx b/apps/stats-web/src/app/(home)/DashboardContainer.tsx index 9d374e93d..0e5d985ea 100644 --- a/apps/stats-web/src/app/(home)/DashboardContainer.tsx +++ b/apps/stats-web/src/app/(home)/DashboardContainer.tsx @@ -5,14 +5,14 @@ import { Spinner } from "@akashnetwork/ui/components"; import { Dashboard } from "./Dashboard"; import { Title } from "@/components/Title"; -import { useSelectedNetwork } from "@/hooks/useSelectedNetwork"; import { useMarketData } from "@/queries"; import { useDashboardData } from "@/queries/useDashboardData"; +import { networkStore } from "@/store/network.store"; export const DashboardContainer: React.FunctionComponent = () => { const { data: dashboardData, isLoading: isLoadingDashboardData } = useDashboardData(); const { data: marketData, isLoading: isLoadingMarketData } = useMarketData(); - const selectedNetwork = useSelectedNetwork(); + const selectedNetwork = networkStore.useSelectedNetwork(); const isLoading = isLoadingMarketData || isLoadingDashboardData; return ( diff --git a/apps/stats-web/src/components/layout/CustomProviders.tsx b/apps/stats-web/src/components/layout/CustomProviders.tsx index 6bd86fe45..a330a52c8 100644 --- a/apps/stats-web/src/components/layout/CustomProviders.tsx +++ b/apps/stats-web/src/components/layout/CustomProviders.tsx @@ -12,12 +12,13 @@ import { CustomIntlProvider } from "./CustomIntlProvider"; import { PricingProvider } from "@/context/PricingProvider"; import { customColors } from "@/lib/colors"; import { queryClient } from "@/queries"; +import { store } from "@/store/global.store"; function Providers({ children }: React.PropsWithChildren) { return ( - + diff --git a/apps/stats-web/src/components/layout/NetworkSelect.tsx b/apps/stats-web/src/components/layout/NetworkSelect.tsx index 8f5b9bca0..c2f57fe03 100644 --- a/apps/stats-web/src/components/layout/NetworkSelect.tsx +++ b/apps/stats-web/src/components/layout/NetworkSelect.tsx @@ -1,50 +1,22 @@ "use client"; -import React, { useEffect, useState } from "react"; -import { MAINNET_ID, Network } from "@akashnetwork/network-store"; +import React from "react"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Spinner } from "@akashnetwork/ui/components"; -import { setNetworkVersion } from "@/lib/constants"; import { cn } from "@/lib/utils"; -import { initiateNetworkData, networks } from "@/store/networkStore"; +import { networkStore } from "@/store/network.store"; interface NetworkSelectProps { className?: string; } const NetworkSelect: React.FC = ({ className }) => { - const [isLoadingSettings, setIsLoadingSettings] = useState(true); - const [selectedNetworkId, setSelectedNetworkId] = useState(MAINNET_ID); - - useEffect(() => { - async function init() { - await initiateNetworkData(); - setNetworkVersion(); - - const selectedNetworkId = localStorage.getItem("selectedNetworkId") as Network["id"]; - if (selectedNetworkId) { - setSelectedNetworkId(selectedNetworkId); - } - - setIsLoadingSettings(false); - } - - init(); - }, []); - - const onSelectNetworkChange = (networkId: Network["id"]) => { - setSelectedNetworkId(networkId); - - // Set in the settings and local storage - localStorage.setItem("selectedNetworkId", networkId); - // Reset the ui to reload the settings for the currently selected network - - location.reload(); - }; + const [{ isLoading: isLoadingNetworks, data: networks }] = networkStore.useNetworksStore(); + const [selectedNetworkId, setSelectedNetworkId] = networkStore.useSelectedNetworkIdStore({ reloadOnChange: true }); return ( - - {isLoadingSettings && } + {isLoadingNetworks && } diff --git a/apps/stats-web/src/config/browser-env.config.ts b/apps/stats-web/src/config/browser-env.config.ts new file mode 100644 index 000000000..785dfe72f --- /dev/null +++ b/apps/stats-web/src/config/browser-env.config.ts @@ -0,0 +1,6 @@ +import { validateStaticEnvVars } from "./env-config.schema"; + +export const browserEnvConfig = validateStaticEnvVars({ + NEXT_PUBLIC_DEFAULT_NETWORK_ID: process.env.NEXT_PUBLIC_DEFAULT_NETWORK_ID, + NEXT_PUBLIC_API_BASE_URL: process.env.NEXT_PUBLIC_API_BASE_URL +}); diff --git a/apps/stats-web/src/config/env-config.schema.ts b/apps/stats-web/src/config/env-config.schema.ts new file mode 100644 index 000000000..9575f793e --- /dev/null +++ b/apps/stats-web/src/config/env-config.schema.ts @@ -0,0 +1,29 @@ +import { z } from "zod"; + +const networkId = z.enum(["mainnet", "sandbox", "testnet"]); +const coercedBoolean = () => z.enum(["true", "false"]).transform(val => val === "true"); + +export const browserEnvSchema = z.object({ + NEXT_PUBLIC_DEFAULT_NETWORK_ID: networkId.optional().default("mainnet"), + NEXT_PUBLIC_API_BASE_URL: z.string().url() +}); + +export const serverEnvSchema = browserEnvSchema.extend({ + MAINTENANCE_MODE: coercedBoolean().optional().default("false"), + BASE_API_MAINNET_URL: z.string().url(), + BASE_API_TESTNET_URL: z.string().url(), + BASE_API_SANDBOX_URL: z.string().url() +}); + +export type BrowserEnvConfig = z.infer; +export type ServerEnvConfig = z.infer; + +export const validateStaticEnvVars = (config: Record) => browserEnvSchema.parse(config); +export const validateRuntimeEnvVars = (config: Record) => { + if (process.env.NEXT_PHASE === "phase-production-build") { + console.log("Skipping validation of serverEnvConfig during build"); + return config as ServerEnvConfig; + } else { + return serverEnvSchema.parse(config); + } +}; diff --git a/apps/stats-web/src/config/server-env.config.ts b/apps/stats-web/src/config/server-env.config.ts new file mode 100644 index 000000000..1b85264cc --- /dev/null +++ b/apps/stats-web/src/config/server-env.config.ts @@ -0,0 +1,5 @@ +import "@akashnetwork/env-loader"; + +import { validateRuntimeEnvVars } from "./env-config.schema"; + +export const serverEnvConfig = validateRuntimeEnvVars(process.env); diff --git a/apps/stats-web/src/hooks/useDenom.ts b/apps/stats-web/src/hooks/useDenom.ts index 3a2f76265..d53706f8f 100644 --- a/apps/stats-web/src/hooks/useDenom.ts +++ b/apps/stats-web/src/hooks/useDenom.ts @@ -1,8 +1,7 @@ -import { useSelectedNetwork } from "./useSelectedNetwork"; - import { USDC_IBC_DENOMS } from "@/config/denom.config"; +import { networkStore } from "@/store/network.store"; export const useUsdcDenom = () => { - const selectedNetwork = useSelectedNetwork(); - return USDC_IBC_DENOMS[selectedNetwork.id]; + const selectedNetworkId = networkStore.useSelectedNetworkId(); + return USDC_IBC_DENOMS[selectedNetworkId]; }; diff --git a/apps/stats-web/src/hooks/useSelectedNetwork.ts b/apps/stats-web/src/hooks/useSelectedNetwork.ts deleted file mode 100644 index 83a65c86a..000000000 --- a/apps/stats-web/src/hooks/useSelectedNetwork.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MAINNET_ID } from "@akashnetwork/network-store"; -import { useAtom } from "jotai"; -import { useEffectOnce } from "usehooks-ts"; - -import networkStore, { networks } from "@/store/networkStore"; - -export const getSelectedNetwork = () => { - const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? MAINNET_ID; - const selectedNetwork = networks.find(n => n.id === selectedNetworkId); - - // return mainnet if selected network is not found - return selectedNetwork ?? networks[0]; -}; - -export const useSelectedNetwork = () => { - const [selectedNetwork, setSelectedNetwork] = useAtom(networkStore.selectedNetwork); - - useEffectOnce(() => { - const selectedNetworkId = localStorage.getItem("selectedNetworkId") ?? MAINNET_ID; - setSelectedNetwork(networks.find(n => n.id === selectedNetworkId) || networks[0]); - }); - - return selectedNetwork ?? networks[0]; -}; diff --git a/apps/stats-web/src/lib/constants.ts b/apps/stats-web/src/lib/constants.ts index 151c7e8c9..dab4540e2 100644 --- a/apps/stats-web/src/lib/constants.ts +++ b/apps/stats-web/src/lib/constants.ts @@ -1,4 +1,6 @@ -import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; +import { SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; + +import { networkStore } from "@/store/network.store"; const productionMainnetApiUrl = "https://console-api.akash.network"; const productionTestnetApiUrl = "https://console-api-testnet.akash.network"; @@ -50,8 +52,7 @@ function getApiUrl() { if (typeof window === "undefined") return "http://localhost:3080"; if (productionHostnames.includes(window.location?.hostname)) { try { - const _selectedNetworkId = localStorage.getItem("selectedNetworkId"); - return getNetworkBaseApiUrl(_selectedNetworkId); + return getNetworkBaseApiUrl(networkStore.selectedNetworkId); } catch (e) { console.error(e); return productionMainnetApiUrl; @@ -59,30 +60,3 @@ function getApiUrl() { } return "http://localhost:3080"; } - -export let selectedNetworkId = ""; -export let networkVersion: "v1beta2" | "v1beta3"; - -export function setNetworkVersion() { - const _selectedNetworkId = localStorage.getItem("selectedNetworkId"); - - switch (_selectedNetworkId) { - case MAINNET_ID: - networkVersion = "v1beta3"; - selectedNetworkId = MAINNET_ID; - break; - case TESTNET_ID: - networkVersion = "v1beta3"; - selectedNetworkId = TESTNET_ID; - break; - case SANDBOX_ID: - networkVersion = "v1beta3"; - selectedNetworkId = SANDBOX_ID; - break; - - default: - networkVersion = "v1beta3"; - selectedNetworkId = MAINNET_ID; - break; - } -} diff --git a/apps/stats-web/src/lib/urlUtils.ts b/apps/stats-web/src/lib/urlUtils.ts index d57940e4f..d6e070404 100644 --- a/apps/stats-web/src/lib/urlUtils.ts +++ b/apps/stats-web/src/lib/urlUtils.ts @@ -1,30 +1,20 @@ -import { selectedNetworkId } from "./constants"; - -function getSelectedNetworkQueryParam() { - if (selectedNetworkId) { - return selectedNetworkId; - } else if (typeof window !== "undefined") { - return new URLSearchParams(window.location.search).get("network"); - } - - return undefined; -} +import { networkStore } from "@/store/network.store"; export class UrlService { static home = () => "/"; static graph = (snapshot: string) => `/graph/${snapshot}`; static providerGraph = (snapshot: string) => `/provider-graph/${snapshot}`; static blocks = () => `/blocks`; - static block = (height: number) => `/blocks/${height}${appendSearchParams({ network: getSelectedNetworkQueryParam() as string })}`; + static block = (height: number) => `/blocks/${height}${appendSearchParams({ network: networkStore.selectedNetworkId })}`; static transactions = () => `/transactions`; - static transaction = (hash: string) => `/transactions/${hash}${appendSearchParams({ network: getSelectedNetworkQueryParam() as string })}`; - static address = (address: string) => `/addresses/${address}${appendSearchParams({ network: getSelectedNetworkQueryParam() as string })}`; + static transaction = (hash: string) => `/transactions/${hash}${appendSearchParams({ network: networkStore.selectedNetworkId })}`; + static address = (address: string) => `/addresses/${address}${appendSearchParams({ network: networkStore.selectedNetworkId })}`; static addressTransactions = (address: string) => `/addresses/${address}/transactions`; static addressDeployments = (address: string) => `/addresses/${address}/deployments`; static deployment = (owner: string, dseq: string) => - `/addresses/${owner}/deployments/${dseq}${appendSearchParams({ network: getSelectedNetworkQueryParam() as string })}`; + `/addresses/${owner}/deployments/${dseq}${appendSearchParams({ network: networkStore.selectedNetworkId })}`; static validators = () => "/validators"; - static validator = (address: string) => `/validators/${address}${appendSearchParams({ network: getSelectedNetworkQueryParam() as string })}`; + static validator = (address: string) => `/validators/${address}${appendSearchParams({ network: networkStore.selectedNetworkId })}`; static proposals = () => "/proposals"; static proposal = (id: number) => `/proposals/${id}`; } @@ -64,9 +54,3 @@ export function isValidHttpUrl(str: string): boolean { return url.protocol === "http:" || url.protocol === "https:"; } - -export function handleDocClick(ev: Event, url: string) { - ev.preventDefault(); - - window.open(url, "_blank"); -} diff --git a/apps/stats-web/src/store/global.store.ts b/apps/stats-web/src/store/global.store.ts new file mode 100644 index 000000000..2ff6e1b41 --- /dev/null +++ b/apps/stats-web/src/store/global.store.ts @@ -0,0 +1,3 @@ +import { createStore } from "jotai"; + +export const store = createStore(); diff --git a/apps/stats-web/src/store/network.store.ts b/apps/stats-web/src/store/network.store.ts new file mode 100644 index 000000000..da9ef9579 --- /dev/null +++ b/apps/stats-web/src/store/network.store.ts @@ -0,0 +1,10 @@ +import { NetworkStore } from "@akashnetwork/network-store"; + +import { browserEnvConfig } from "@/config/browser-env.config"; +import { store } from "@/store/global.store"; + +export const networkStore = NetworkStore.create({ + defaultNetworkId: browserEnvConfig.NEXT_PUBLIC_DEFAULT_NETWORK_ID, + apiBaseUrl: browserEnvConfig.NEXT_PUBLIC_API_BASE_URL, + store +}); diff --git a/apps/stats-web/src/store/networkStore.ts b/apps/stats-web/src/store/networkStore.ts deleted file mode 100644 index 9b02b4107..000000000 --- a/apps/stats-web/src/store/networkStore.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; -import axios from "axios"; -import { atom } from "jotai"; - -import { ApiUrlService } from "@/lib/apiUtils"; -import { Network } from "@/types/network"; - -export let networks: Network[] = [ - { - id: MAINNET_ID, - title: "Mainnet", - description: "Akash Network mainnet network.", - chainId: "akashnet-2", - versionUrl: ApiUrlService.mainnetVersion(), - rpcEndpoint: "https://rpc.cosmos.directory/akash", - enabled: true, - version: null // Set asynchronously - }, - { - id: TESTNET_ID, - title: "GPU Testnet", - description: "Testnet of the new GPU features.", - chainId: "testnet-02", - versionUrl: ApiUrlService.testnetVersion(), - enabled: false, - version: null // Set asynchronously - }, - { - id: SANDBOX_ID, - title: "Sandbox", - description: "Sandbox of the mainnet version.", - chainId: "sandbox-01", - versionUrl: ApiUrlService.sandboxVersion(), - version: null, // Set asynchronously - enabled: true - } -]; - -/** - * Get the actual versions and metadata of the available networks - */ -export const initiateNetworkData = async () => { - networks = await Promise.all( - networks.map(async network => { - let version = null; - try { - const response = await axios.get(network.versionUrl, { timeout: 10000 }); - version = response.data; - } catch (error) { - console.log(error); - } - - return { - ...network, - version - }; - }) - ); -}; - -const selectedNetwork = atom(networks[0]); - -const networkStore = { - selectedNetwork -}; - -export default networkStore; diff --git a/packages/network-store/src/network.store.ts b/packages/network-store/src/network.store.ts index f756f8069..87e8f91e4 100644 --- a/packages/network-store/src/network.store.ts +++ b/packages/network-store/src/network.store.ts @@ -33,7 +33,7 @@ export class NetworkStore { readonly networksStore = atom({ isLoading: true, error: undefined, data: INITIAL_NETWORKS_CONFIG }); - private readonly selectedNetworkIdStore = atomWithStorage("selectedNetworkId", this.options.defaultNetworkId, undefined, { getOnInit: true }); + private readonly selectedNetworkIdStore = atomWithStorage("selectedNetworkId", this.getInitialNetworkId()); private readonly selectedNetworkStore = atom( get => { @@ -42,8 +42,8 @@ export class NetworkStore { return networks.find(n => n.id === networkId) ?? networks[0]; }, - async (get, set, next) => { - await set(this.selectedNetworkIdStore, next.id); + (get, set, next) => { + set(this.selectedNetworkIdStore, next.id); } ); @@ -101,6 +101,26 @@ export class NetworkStore { } } + private getInitialNetworkId(): Network["id"] { + if (typeof window === "undefined") { + return this.options.defaultNetworkId; + } + + const url = new URL(window.location.href); + + if (!url.searchParams.has("network")) { + return this.options.defaultNetworkId; + } + + const raw = url.searchParams.get("network"); + + if (this.networks.some(({ id }) => id === raw)) { + return raw as Network["id"]; + } + + return this.options.defaultNetworkId; + } + useNetworksStore() { return useAtom(this.networksStore); } From 6cf640dccba598deeb229fd4e2110e1d7e412270 Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 15:33:41 +0200 Subject: [PATCH 06/11] feat(config): replace api url definitions with env var configs refs #163, #313 --- apps/stats-web/env/.env.production | 10 ++- apps/stats-web/env/.env.staging | 10 ++- apps/stats-web/package.json | 2 +- .../[address]/deployments/[dseq]/page.tsx | 33 ++++++--- .../src/app/addresses/[address]/page.tsx | 35 ++++++--- .../src/app/blocks/[height]/page.tsx | 34 ++++++--- .../src/app/transactions/[hash]/page.tsx | 41 +++++++---- .../src/app/validators/[address]/page.tsx | 36 ++++++---- .../layout/CustomGoogleAnalytics.tsx | 4 +- .../src/config/browser-env.config.ts | 6 +- .../stats-web/src/config/env-config.schema.ts | 8 ++- apps/stats-web/src/lib/apiUtils.ts | 72 ++++++------------- apps/stats-web/src/lib/constants.ts | 62 ---------------- .../src/services/api-url/api-url.service.ts | 36 ++++++++++ .../api-url/browser-api-url.service.ts | 4 ++ .../api-url/server-api-url.service.ts | 4 ++ packages/network-store/package.json | 3 +- packages/network-store/src/network.store.ts | 22 +++--- 18 files changed, 232 insertions(+), 190 deletions(-) delete mode 100644 apps/stats-web/src/lib/constants.ts create mode 100644 apps/stats-web/src/services/api-url/api-url.service.ts create mode 100644 apps/stats-web/src/services/api-url/browser-api-url.service.ts create mode 100644 apps/stats-web/src/services/api-url/server-api-url.service.ts diff --git a/apps/stats-web/env/.env.production b/apps/stats-web/env/.env.production index dbd0c6496..dd649e84e 100644 --- a/apps/stats-web/env/.env.production +++ b/apps/stats-web/env/.env.production @@ -1 +1,9 @@ -NEXT_PUBLIC_API_BASE_URL=https://console-api.akash.network \ No newline at end of file +NEXT_PUBLIC_NODE_ENV=$NODE_ENV +NEXT_PUBLIC_BASE_API_MAINNET_URL=https://console-api.akash.network +NEXT_PUBLIC_BASE_API_SANDBOX_URL=https://console-api-sandbox.akash.network +NEXT_PUBLIC_BASE_API_TESTNET_URL=https://console-api-testnet.akash.network +NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_BASE_API_MAINNET_URL + +BASE_API_MAINNET_URL=$NEXT_PUBLIC_BASE_API_MAINNET_URL +BASE_API_TESTNET_URL=$NEXT_PUBLIC_BASE_API_TESTNET_URL +BASE_API_SANDBOX_URL=$NEXT_PUBLIC_BASE_API_SANDBOX_URL \ No newline at end of file diff --git a/apps/stats-web/env/.env.staging b/apps/stats-web/env/.env.staging index 968b942c0..3778aa132 100644 --- a/apps/stats-web/env/.env.staging +++ b/apps/stats-web/env/.env.staging @@ -1 +1,9 @@ -NEXT_PUBLIC_API_BASE_URL=https://console-api-mainnet-staging.akash.network \ No newline at end of file +NEXT_PUBLIC_NODE_ENV=$NODE_ENV +NEXT_PUBLIC_BASE_API_MAINNET_URL=https://console-api-mainnet-staging.akash.network +NEXT_PUBLIC_BASE_API_SANDBOX_URL=https://console-api-sandbox-staging.akash.network +NEXT_PUBLIC_BASE_API_TESTNET_URL=$NEXT_PUBLIC_BASE_API_MAINNET_URL +NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_BASE_API_MAINNET_URL + +BASE_API_MAINNET_URL=$NEXT_PUBLIC_BASE_API_MAINNET_URL +BASE_API_TESTNET_URL=$NEXT_PUBLIC_BASE_API_TESTNET_URL +BASE_API_SANDBOX_URL=$NEXT_PUBLIC_BASE_API_SANDBOX_URL \ No newline at end of file diff --git a/apps/stats-web/package.json b/apps/stats-web/package.json index 7134d2993..c9a54267f 100644 --- a/apps/stats-web/package.json +++ b/apps/stats-web/package.json @@ -11,8 +11,8 @@ "start": "next start" }, "dependencies": { - "@akashnetwork/ui": "*", "@akashnetwork/network-store": "*", + "@akashnetwork/ui": "*", "@cosmjs/encoding": "^0.32.4", "@json2csv/plainjs": "^7.0.4", "@nivo/line": "^0.87.0", diff --git a/apps/stats-web/src/app/addresses/[address]/deployments/[dseq]/page.tsx b/apps/stats-web/src/app/addresses/[address]/deployments/[dseq]/page.tsx index 71f6cf4bf..0dac31a87 100644 --- a/apps/stats-web/src/app/addresses/[address]/deployments/[dseq]/page.tsx +++ b/apps/stats-web/src/app/addresses/[address]/deployments/[dseq]/page.tsx @@ -1,19 +1,28 @@ +import type { Network } from "@akashnetwork/network-store"; import { Metadata } from "next"; +import { z } from "zod"; import { DeploymentInfo } from "./DeploymentInfo"; import PageContainer from "@/components/PageContainer"; import { Title } from "@/components/Title"; -import { getNetworkBaseApiUrl } from "@/lib/constants"; +import { networkId } from "@/config/env-config.schema"; import { UrlService } from "@/lib/urlUtils"; +import { serverApiUrlService } from "@/services/api-url/server-api-url.service"; import { DeploymentDetail } from "@/types"; -interface IProps { - params: { address: string; dseq: string }; - searchParams: { [key: string]: string | string[] | undefined }; -} +const DeploymentDetailPageSchema = z.object({ + params: z.object({ + address: z.string(), + dseq: z.string() + }), + searchParams: z.object({ + network: networkId + }) +}); +type DeploymentDetailPageProps = z.infer; -export async function generateMetadata({ params: { address, dseq } }: IProps): Promise { +export async function generateMetadata({ params: { address, dseq } }: DeploymentDetailPageProps): Promise { const url = `https://stats.akash.network${UrlService.deployment(address, dseq)}`; return { @@ -27,8 +36,8 @@ export async function generateMetadata({ params: { address, dseq } }: IProps): P }; } -async function fetchDeploymentData(address: string, dseq: string, network: string): Promise { - const apiUrl = getNetworkBaseApiUrl(network); +async function fetchDeploymentData(address: string, dseq: string, network: Network["id"]): Promise { + const apiUrl = serverApiUrlService.getBaseApiUrlFor(network); const response = await fetch(`${apiUrl}/v1/deployment/${address}/${dseq}`); if (!response.ok) { @@ -39,8 +48,12 @@ async function fetchDeploymentData(address: string, dseq: string, network: strin return response.json(); } -export default async function DeploymentDetailPage({ params: { address, dseq }, searchParams: { network } }: IProps) { - const deployment = await fetchDeploymentData(address, dseq, network as string); +export default async function DeploymentDetailPage(props: DeploymentDetailPageProps) { + const { + params: { address, dseq }, + searchParams: { network } + } = DeploymentDetailPageSchema.parse(props); + const deployment = await fetchDeploymentData(address, dseq, network); return ( diff --git a/apps/stats-web/src/app/addresses/[address]/page.tsx b/apps/stats-web/src/app/addresses/[address]/page.tsx index ba0464822..2f26909cb 100644 --- a/apps/stats-web/src/app/addresses/[address]/page.tsx +++ b/apps/stats-web/src/app/addresses/[address]/page.tsx @@ -1,4 +1,6 @@ -import { Metadata } from "next"; +import type { Network } from "@akashnetwork/network-store"; +import type { Metadata } from "next"; +import { z } from "zod"; import { AddressInfo } from "./AddressInfo"; import AddressLayout from "./AddressLayout"; @@ -7,16 +9,23 @@ import { AssetList } from "./AssetList"; import { LatestTransactions } from "./LatestTransactions"; import { Title } from "@/components/Title"; -import { getNetworkBaseApiUrl } from "@/lib/constants"; +import { networkId } from "@/config/env-config.schema"; import { UrlService } from "@/lib/urlUtils"; +import { serverApiUrlService } from "@/services/api-url/server-api-url.service"; import { AddressDetail } from "@/types"; -interface IProps { - params: { address: string }; - searchParams: { [key: string]: string | string[] | undefined }; -} +const AddressDetailPageSchema = z.object({ + params: z.object({ + address: z.string(), + dseq: z.string() + }), + searchParams: z.object({ + network: networkId + }) +}); +type AddressDetailPageProps = z.infer; -export async function generateMetadata({ params: { address } }: IProps): Promise { +export async function generateMetadata({ params: { address } }: AddressDetailPageProps): Promise { const url = `https://stats.akash.network${UrlService.address(address)}`; return { @@ -30,8 +39,8 @@ export async function generateMetadata({ params: { address } }: IProps): Promise }; } -async function fetchAddressData(address: string, network: string): Promise { - const apiUrl = getNetworkBaseApiUrl(network); +async function fetchAddressData(address: string, network: Network["id"]): Promise { + const apiUrl = serverApiUrlService.getBaseApiUrlFor(network); const response = await fetch(`${apiUrl}/v1/addresses/${address}`); if (!response.ok) { @@ -42,8 +51,12 @@ async function fetchAddressData(address: string, network: string): Promise diff --git a/apps/stats-web/src/app/blocks/[height]/page.tsx b/apps/stats-web/src/app/blocks/[height]/page.tsx index 7f36b23d9..16955584d 100644 --- a/apps/stats-web/src/app/blocks/[height]/page.tsx +++ b/apps/stats-web/src/app/blocks/[height]/page.tsx @@ -1,28 +1,36 @@ +import type { Network } from "@akashnetwork/network-store"; import { Card, CardContent, Table, TableBody, TableHead, TableHeader, TableRow } from "@akashnetwork/ui/components"; import { SearchX } from "lucide-react"; -import { Metadata } from "next"; +import type { Metadata } from "next"; +import { z } from "zod"; import { BlockInfo } from "./BlockInfo"; import { TransactionRow } from "@/components/blockchain/TransactionRow"; import PageContainer from "@/components/PageContainer"; import { Title } from "@/components/Title"; -import { getNetworkBaseApiUrl } from "@/lib/constants"; +import { networkId } from "@/config/env-config.schema"; +import { serverApiUrlService } from "@/services/api-url/server-api-url.service"; import { BlockDetail } from "@/types"; -interface IProps { - params: { height: string }; - searchParams: { [key: string]: string | string[] | undefined }; -} +const BlockDetailPageSchema = z.object({ + params: z.object({ + height: z.string() + }), + searchParams: z.object({ + network: networkId + }) +}); +type BlockDetailPageProps = z.infer; -export async function generateMetadata({ params: { height } }: IProps): Promise { +export async function generateMetadata({ params: { height } }: BlockDetailPageProps): Promise { return { title: `Block #${height}` }; } -async function fetchBlockData(height: string, network: string): Promise { - const apiUrl = getNetworkBaseApiUrl(network); +async function fetchBlockData(height: string, network: Network["id"]): Promise { + const apiUrl = serverApiUrlService.getBaseApiUrlFor(network); const response = await fetch(`${apiUrl}/v1/blocks/${height}`); if (!response.ok) { @@ -33,8 +41,12 @@ async function fetchBlockData(height: string, network: string): Promise diff --git a/apps/stats-web/src/app/transactions/[hash]/page.tsx b/apps/stats-web/src/app/transactions/[hash]/page.tsx index f63fd61ec..76bc605b6 100644 --- a/apps/stats-web/src/app/transactions/[hash]/page.tsx +++ b/apps/stats-web/src/app/transactions/[hash]/page.tsx @@ -1,35 +1,44 @@ import React from "react"; +import type { Network } from "@akashnetwork/network-store"; import { Alert, Card, CardContent } from "@akashnetwork/ui/components"; -import { Metadata } from "next"; +import type { Metadata } from "next"; +import { z } from "zod"; import { TransactionInfo } from "./TransactionInfo"; import PageContainer from "@/components/PageContainer"; import { Title } from "@/components/Title"; import { TxMessageRow } from "@/components/transactions/TxMessageRow"; +import { networkId } from "@/config/env-config.schema"; import { getSplitText } from "@/hooks/useShortText"; -import { getNetworkBaseApiUrl } from "@/lib/constants"; +import { serverApiUrlService } from "@/services/api-url/server-api-url.service"; import { TransactionDetail } from "@/types"; -interface IProps { - params: { hash: string }; - searchParams: { [key: string]: string | string[] | undefined }; -} +const TransactionDetailPageSchema = z.object({ + params: z.object({ + hash: z.string() + }), + searchParams: z.object({ + network: networkId + }) +}); +type TransactionDetailPageProps = z.infer; -export async function generateMetadata({ params: { hash } }: IProps): Promise { - const splittedTxHash = getSplitText(hash, 6, 6); +export async function generateMetadata({ params: { hash } }: TransactionDetailPageProps): Promise { + const splitTxHash = getSplitText(hash, 6, 6); return { - title: `Tx ${splittedTxHash}` + title: `Tx ${splitTxHash}` }; } -async function fetchTransactionData(hash: string, network: string): Promise { - const apiUrl = getNetworkBaseApiUrl(network); +async function fetchTransactionData(hash: string, network: Network["id"]): Promise { + const apiUrl = serverApiUrlService.getBaseApiUrlFor(network); + console.log("DEBUG apiUrl", apiUrl); const response = await fetch(`${apiUrl}/v1/transactions/${hash}`); if (!response.ok && response.status !== 404) { // This will activate the closest `error.js` Error Boundary - throw new Error("Error fetching transction data"); + throw new Error("Error fetching transaction data"); } else if (response.status === 404) { return null; } @@ -37,8 +46,12 @@ async function fetchTransactionData(hash: string, network: string): Promise diff --git a/apps/stats-web/src/app/validators/[address]/page.tsx b/apps/stats-web/src/app/validators/[address]/page.tsx index 079793141..4a0f68b38 100644 --- a/apps/stats-web/src/app/validators/[address]/page.tsx +++ b/apps/stats-web/src/app/validators/[address]/page.tsx @@ -1,21 +1,29 @@ -import { Metadata } from "next"; +import type { Network } from "@akashnetwork/network-store"; +import type { Metadata } from "next"; +import { z } from "zod"; import { ValidatorsInfo } from "./ValidatorInfo"; import PageContainer from "@/components/PageContainer"; import { Title } from "@/components/Title"; -import { getNetworkBaseApiUrl } from "@/lib/constants"; +import { networkId } from "@/config/env-config.schema"; import { UrlService } from "@/lib/urlUtils"; +import { serverApiUrlService } from "@/services/api-url/server-api-url.service"; import { ValidatorDetail } from "@/types"; -interface IProps { - params: { address: string }; - searchParams: { [key: string]: string | string[] | undefined }; -} +const ValidatorDetailPageSchema = z.object({ + params: z.object({ + address: z.string() + }), + searchParams: z.object({ + network: networkId + }) +}); +type ValidatorDetailPageProps = z.infer; -export async function generateMetadata({ params: { address }, searchParams: { network } }: IProps): Promise { +export async function generateMetadata({ params: { address }, searchParams: { network } }: ValidatorDetailPageProps): Promise { const url = `https://stats.akash.network${UrlService.validator(address)}`; - const apiUrl = getNetworkBaseApiUrl(network as string); + const apiUrl = serverApiUrlService.getBaseApiUrlFor(network); const response = await fetch(`${apiUrl}/v1/validators/${address}`); const data = (await response.json()) as ValidatorDetail; @@ -30,8 +38,8 @@ export async function generateMetadata({ params: { address }, searchParams: { ne }; } -async function fetchValidatorData(address: string, network: string): Promise { - const apiUrl = getNetworkBaseApiUrl(network); +async function fetchValidatorData(address: string, network: Network["id"]): Promise { + const apiUrl = serverApiUrlService.getBaseApiUrlFor(network); const response = await fetch(`${apiUrl}/v1/validators/${address}`); if (!response.ok) { @@ -42,8 +50,12 @@ async function fetchValidatorData(address: string, network: string): Promise diff --git a/apps/stats-web/src/components/layout/CustomGoogleAnalytics.tsx b/apps/stats-web/src/components/layout/CustomGoogleAnalytics.tsx index 18299f77f..e9c65409c 100644 --- a/apps/stats-web/src/components/layout/CustomGoogleAnalytics.tsx +++ b/apps/stats-web/src/components/layout/CustomGoogleAnalytics.tsx @@ -3,7 +3,7 @@ import { useReportWebVitals } from "next/web-vitals"; import { event, GoogleAnalytics as GAnalytics } from "nextjs-google-analytics"; -import { isProd } from "@/lib/constants"; +import { browserEnvConfig } from "@/config/browser-env.config"; export default function GoogleAnalytics() { useReportWebVitals(({ id, name, label, value }) => { @@ -15,5 +15,5 @@ export default function GoogleAnalytics() { }); }); - return <>{isProd && }; + return <>{browserEnvConfig.NEXT_PUBLIC_NODE_ENV === "production" && }; } diff --git a/apps/stats-web/src/config/browser-env.config.ts b/apps/stats-web/src/config/browser-env.config.ts index 785dfe72f..903fec82c 100644 --- a/apps/stats-web/src/config/browser-env.config.ts +++ b/apps/stats-web/src/config/browser-env.config.ts @@ -2,5 +2,9 @@ import { validateStaticEnvVars } from "./env-config.schema"; export const browserEnvConfig = validateStaticEnvVars({ NEXT_PUBLIC_DEFAULT_NETWORK_ID: process.env.NEXT_PUBLIC_DEFAULT_NETWORK_ID, - NEXT_PUBLIC_API_BASE_URL: process.env.NEXT_PUBLIC_API_BASE_URL + NEXT_PUBLIC_API_BASE_URL: process.env.NEXT_PUBLIC_API_BASE_URL, + NEXT_PUBLIC_NODE_ENV: process.env.NEXT_PUBLIC_NODE_ENV, + NEXT_PUBLIC_BASE_API_TESTNET_URL: process.env.NEXT_PUBLIC_BASE_API_TESTNET_URL, + NEXT_PUBLIC_BASE_API_SANDBOX_URL: process.env.NEXT_PUBLIC_BASE_API_SANDBOX_URL, + NEXT_PUBLIC_BASE_API_MAINNET_URL: process.env.NEXT_PUBLIC_BASE_API_MAINNET_URL }); diff --git a/apps/stats-web/src/config/env-config.schema.ts b/apps/stats-web/src/config/env-config.schema.ts index 9575f793e..1cb77e54f 100644 --- a/apps/stats-web/src/config/env-config.schema.ts +++ b/apps/stats-web/src/config/env-config.schema.ts @@ -1,11 +1,15 @@ import { z } from "zod"; -const networkId = z.enum(["mainnet", "sandbox", "testnet"]); +export const networkId = z.enum(["mainnet", "sandbox", "testnet"]); const coercedBoolean = () => z.enum(["true", "false"]).transform(val => val === "true"); export const browserEnvSchema = z.object({ NEXT_PUBLIC_DEFAULT_NETWORK_ID: networkId.optional().default("mainnet"), - NEXT_PUBLIC_API_BASE_URL: z.string().url() + NEXT_PUBLIC_API_BASE_URL: z.string().url(), + NEXT_PUBLIC_NODE_ENV: z.enum(["development", "production", "test"]).optional().default("development"), + NEXT_PUBLIC_BASE_API_TESTNET_URL: z.string().url(), + NEXT_PUBLIC_BASE_API_SANDBOX_URL: z.string().url(), + NEXT_PUBLIC_BASE_API_MAINNET_URL: z.string().url() }); export const serverEnvSchema = browserEnvSchema.extend({ diff --git a/apps/stats-web/src/lib/apiUtils.ts b/apps/stats-web/src/lib/apiUtils.ts index 87c6a5739..484ee4585 100644 --- a/apps/stats-web/src/lib/apiUtils.ts +++ b/apps/stats-web/src/lib/apiUtils.ts @@ -1,87 +1,57 @@ -import axios from "axios"; - -import { BASE_API_URL } from "./constants"; import { appendSearchParams } from "./urlUtils"; +import { browserApiUrlService } from "@/services/api-url/browser-api-url.service"; +import { networkStore } from "@/store/network.store"; + export class ApiUrlService { static dashboardData() { - return `${BASE_API_URL}/v1/dashboard-data`; + return `${this.baseApiUrl}/v1/dashboard-data`; } static marketData() { - return `${BASE_API_URL}/v1/market-data`; + return `${this.baseApiUrl}/v1/market-data`; } static proposals() { - return `${BASE_API_URL}/v1/proposals`; + return `${this.baseApiUrl}/v1/proposals`; } static validators() { - return `${BASE_API_URL}/v1/validators`; + return `${this.baseApiUrl}/v1/validators`; } static transactions(limit: number) { - return `${BASE_API_URL}/v1/transactions${appendSearchParams({ limit })}`; + return `${this.baseApiUrl}/v1/transactions${appendSearchParams({ limit })}`; } static addressTransactions(address: string, skip: number, limit: number) { - return `${BASE_API_URL}/v1/addresses/${address}/transactions/${skip}/${limit}`; + return `${this.baseApiUrl}/v1/addresses/${address}/transactions/${skip}/${limit}`; } static addressDeployments(address: string, skip: number, limit: number, reverseSorting: boolean, filters: { [key: string]: string }) { - return `${BASE_API_URL}/v1/addresses/${address}/deployments/${skip}/${limit}${appendSearchParams({ reverseSorting, ...filters })}`; + return `${this.baseApiUrl}/v1/addresses/${address}/deployments/${skip}/${limit}${appendSearchParams({ reverseSorting, ...filters })}`; } static graphData(snapshot: string) { - return `${BASE_API_URL}/v1/graph-data/${snapshot}`; + return `${this.baseApiUrl}/v1/graph-data/${snapshot}`; } static providerGraphData(snapshot: string) { - return `${BASE_API_URL}/v1/provider-graph-data/${snapshot}`; + return `${this.baseApiUrl}/v1/provider-graph-data/${snapshot}`; } static blocks(limit: number) { - return `${BASE_API_URL}/v1/blocks${appendSearchParams({ limit })}`; + return `${this.baseApiUrl}/v1/blocks${appendSearchParams({ limit })}`; } static providerAttributesSchema() { - return `${BASE_API_URL}/v1/provider-attributes-schema`; + return `${this.baseApiUrl}/v1/provider-attributes-schema`; } static networkCapacity() { - return `${BASE_API_URL}/v1/network-capacity`; + return `${this.baseApiUrl}/v1/network-capacity`; } static mainnetVersion() { - return `${BASE_API_URL}/v1/version/mainnet`; + return `${this.baseApiUrl}/v1/version/mainnet`; } static testnetVersion() { - return `${BASE_API_URL}/v1/version/testnet`; + return `${this.baseApiUrl}/v1/version/testnet`; } static sandboxVersion() { - return `${BASE_API_URL}/v1/version/sandbox`; + return `${this.baseApiUrl}/v1/version/sandbox`; } -} - -export async function loadWithPagination(baseUrl: string, dataKey: string, limit: number) { - let items: any[] = []; - let nextKey = null; - // let callCount = 1; - // let totalCount = null; - - do { - const _hasQueryParam = hasQueryParam(baseUrl); - let queryUrl = `${baseUrl}${_hasQueryParam ? "&" : "?"}pagination.limit=${limit}&pagination.count_total=true`; - if (nextKey) { - queryUrl += "&pagination.key=" + encodeURIComponent(nextKey); - } - // console.log(`Querying ${dataKey} [${callCount}] from : ${queryUrl}`); - const response = await axios.get(queryUrl); - const data = response.data; - - // if (!nextKey) { - // totalCount = data.pagination.total; - // } - items = items.concat(data[dataKey]); - nextKey = data.pagination.next_key; - // callCount++; - - // console.log(`Got ${items.length} of ${totalCount}`); - } while (nextKey); - - return items.filter(item => item); -} - -function hasQueryParam(url: string) { - return /[?&]/gm.test(url); + static get baseApiUrl() { + return browserApiUrlService.getBaseApiUrlFor(networkStore.selectedNetworkId); + } } diff --git a/apps/stats-web/src/lib/constants.ts b/apps/stats-web/src/lib/constants.ts deleted file mode 100644 index dab4540e2..000000000 --- a/apps/stats-web/src/lib/constants.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; - -import { networkStore } from "@/store/network.store"; - -const productionMainnetApiUrl = "https://console-api.akash.network"; -const productionTestnetApiUrl = "https://console-api-testnet.akash.network"; -const productionSandboxApiUrl = "https://console-api-sandbox.akash.network"; -const productionHostnames = ["stats.akash.network"]; - -export const isProd = process.env.NODE_ENV === "production"; -export const isMaintenanceMode = process.env.MAINTENANCE_MODE === "true"; -export const BASE_API_MAINNET_URL = getApiMainnetUrl(); -export const BASE_API_TESTNET_URL = getApiTestnetUrl(); -export const BASE_API_SANDBOX_URL = getApiSandboxUrl(); - -export const BASE_API_URL = getApiUrl(); - -export function getNetworkBaseApiUrl(network: string | null) { - switch (network) { - case TESTNET_ID: - return BASE_API_TESTNET_URL; - case SANDBOX_ID: - return BASE_API_SANDBOX_URL; - default: - return BASE_API_MAINNET_URL; - } -} - -function getApiMainnetUrl() { - if (process.env.API_MAINNET_BASE_URL) return process.env.API_MAINNET_BASE_URL; - if (typeof window === "undefined") return "http://localhost:3080"; - if (productionHostnames.includes(window.location?.hostname)) return productionMainnetApiUrl; - return "http://localhost:3080"; -} - -function getApiTestnetUrl() { - if (process.env.API_TESTNET_BASE_URL) return process.env.API_TESTNET_BASE_URL; - if (typeof window === "undefined") return "http://localhost:3080"; - if (productionHostnames.includes(window.location?.hostname)) return productionTestnetApiUrl; - return "http://localhost:3080"; -} - -function getApiSandboxUrl() { - if (process.env.API_SANDBOX_BASE_URL) return process.env.API_SANDBOX_BASE_URL; - if (typeof window === "undefined") return "http://localhost:3080"; - if (productionHostnames.includes(window.location?.hostname)) return productionSandboxApiUrl; - return "http://localhost:3080"; -} - -function getApiUrl() { - if (process.env.API_BASE_URL) return process.env.API_BASE_URL; - if (typeof window === "undefined") return "http://localhost:3080"; - if (productionHostnames.includes(window.location?.hostname)) { - try { - return getNetworkBaseApiUrl(networkStore.selectedNetworkId); - } catch (e) { - console.error(e); - return productionMainnetApiUrl; - } - } - return "http://localhost:3080"; -} diff --git a/apps/stats-web/src/services/api-url/api-url.service.ts b/apps/stats-web/src/services/api-url/api-url.service.ts new file mode 100644 index 000000000..5c13fb9cd --- /dev/null +++ b/apps/stats-web/src/services/api-url/api-url.service.ts @@ -0,0 +1,36 @@ +import type { NetworkId } from "@akashnetwork/akashjs/build/types/network"; +import { SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store"; + +import type { BrowserEnvConfig, ServerEnvConfig } from "@/config/env-config.schema"; + +export class ApiUrlService { + constructor( + private readonly config: + | Pick + | Pick + ) {} + + getBaseApiUrlFor(network: NetworkId) { + if ("BASE_API_MAINNET_URL" in this.config) { + switch (network) { + case TESTNET_ID: + return this.config.BASE_API_TESTNET_URL; + case SANDBOX_ID: + return this.config.BASE_API_SANDBOX_URL; + default: + return this.config.BASE_API_MAINNET_URL; + } + } + + if ("NEXT_PUBLIC_BASE_API_MAINNET_URL" in this.config) { + switch (network) { + case TESTNET_ID: + return this.config.NEXT_PUBLIC_BASE_API_TESTNET_URL; + case SANDBOX_ID: + return this.config.NEXT_PUBLIC_BASE_API_SANDBOX_URL; + default: + return this.config.NEXT_PUBLIC_BASE_API_MAINNET_URL; + } + } + } +} diff --git a/apps/stats-web/src/services/api-url/browser-api-url.service.ts b/apps/stats-web/src/services/api-url/browser-api-url.service.ts new file mode 100644 index 000000000..ca1a02faf --- /dev/null +++ b/apps/stats-web/src/services/api-url/browser-api-url.service.ts @@ -0,0 +1,4 @@ +import { browserEnvConfig } from "@/config/browser-env.config"; +import { ApiUrlService } from "@/services/api-url/api-url.service"; + +export const browserApiUrlService = new ApiUrlService(browserEnvConfig); diff --git a/apps/stats-web/src/services/api-url/server-api-url.service.ts b/apps/stats-web/src/services/api-url/server-api-url.service.ts new file mode 100644 index 000000000..5b17432a7 --- /dev/null +++ b/apps/stats-web/src/services/api-url/server-api-url.service.ts @@ -0,0 +1,4 @@ +import { serverEnvConfig } from "@/config/server-env.config"; +import { ApiUrlService } from "@/services/api-url/api-url.service"; + +export const serverApiUrlService = new ApiUrlService(serverEnvConfig); diff --git a/packages/network-store/package.json b/packages/network-store/package.json index 4959ea4b8..b7ea9e61b 100644 --- a/packages/network-store/package.json +++ b/packages/network-store/package.json @@ -11,7 +11,8 @@ "lint": "eslint ." }, "dependencies": { - "axios": "^1.7.2" + "axios": "^1.7.2", + "lodash": "^4.17.21" }, "devDependencies": { "@akashnetwork/akashjs": "^0.10.0" diff --git a/packages/network-store/src/network.store.ts b/packages/network-store/src/network.store.ts index 87e8f91e4..f919c4a90 100644 --- a/packages/network-store/src/network.store.ts +++ b/packages/network-store/src/network.store.ts @@ -2,6 +2,7 @@ import axios from "axios"; import { atom } from "jotai"; import { getDefaultStore, useAtom } from "jotai"; import { atomWithStorage } from "jotai/utils"; +import cloneDeep from "lodash/cloneDeep"; import { INITIAL_NETWORKS_CONFIG } from "./network.config"; import type { Network } from "./network.type"; @@ -31,9 +32,11 @@ export class NetworkStore { return new NetworkStore(options); } - readonly networksStore = atom({ isLoading: true, error: undefined, data: INITIAL_NETWORKS_CONFIG }); + private readonly STORAGE_KEY = "selectedNetworkId"; - private readonly selectedNetworkIdStore = atomWithStorage("selectedNetworkId", this.getInitialNetworkId()); + readonly networksStore = atom({ isLoading: true, error: undefined, data: cloneDeep(INITIAL_NETWORKS_CONFIG) }); + + private readonly selectedNetworkIdStore = atomWithStorage(this.STORAGE_KEY, this.options.defaultNetworkId); private readonly selectedNetworkStore = atom( get => { @@ -71,13 +74,14 @@ export class NetworkStore { constructor(private readonly options: NetworkStoreOptions) { this.store = options.store || getDefaultStore(); + this.initiateNetworkFromUrlQuery(); this.initiateNetworks(); } private async initiateNetworks() { const errors: { network: Network; error: Error }[] = []; const networks = await Promise.all( - INITIAL_NETWORKS_CONFIG.map(async network => { + cloneDeep(INITIAL_NETWORKS_CONFIG).map(async network => { try { network.versionUrl = this.options.apiBaseUrl + network.versionUrl; network.nodesUrl = this.options.apiBaseUrl + network.nodesUrl; @@ -101,24 +105,22 @@ export class NetworkStore { } } - private getInitialNetworkId(): Network["id"] { + private initiateNetworkFromUrlQuery(): Network["id"] { if (typeof window === "undefined") { - return this.options.defaultNetworkId; + return; } const url = new URL(window.location.href); if (!url.searchParams.has("network")) { - return this.options.defaultNetworkId; + return; } const raw = url.searchParams.get("network"); - if (this.networks.some(({ id }) => id === raw)) { - return raw as Network["id"]; + if (INITIAL_NETWORKS_CONFIG.some(({ id }) => id === raw)) { + window.localStorage.setItem(this.STORAGE_KEY, JSON.stringify(raw)); } - - return this.options.defaultNetworkId; } useNetworksStore() { From 2b61992f9f9095e98764177dfd27f9dc0d2e11a7 Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 15:53:11 +0200 Subject: [PATCH 07/11] ci(config): adjust ci build for stats-web refs #163, #313 --- .dockerignore | 1 - .github/workflows/docker-build-stats-web.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 9c820219e..68d7baa79 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,7 +12,6 @@ apps/indexer/.env* apps/landing/.env* apps/provider-console/.env* apps/provider-proxy/.env* -apps/stats-web/.env* **/.next *.md diff --git a/.github/workflows/docker-build-stats-web.yml b/.github/workflows/docker-build-stats-web.yml index 9d822b542..13c13133e 100644 --- a/.github/workflows/docker-build-stats-web.yml +++ b/.github/workflows/docker-build-stats-web.yml @@ -24,4 +24,4 @@ jobs: - name: Build the Docker image if: steps.filter.outputs.stats-web == 'true' - run: npm run dc:build -- stats-web + run: npm run dc:build -- --build-arg DEPLOYMENT_ENV=production stats-web From 3f9626335be78fba6578c0df2c640e0f092fabb0 Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Tue, 8 Oct 2024 09:34:56 +0200 Subject: [PATCH 08/11] fix: update package-lock.json --- package-lock.json | 193 +++++++--------------------------------------- 1 file changed, 30 insertions(+), 163 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed7f9310f..c99691fe0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -726,6 +726,7 @@ "apps/stats-web": { "version": "0.20.0", "dependencies": { + "@akashnetwork/network-store": "*", "@akashnetwork/ui": "*", "@cosmjs/encoding": "^0.32.4", "@json2csv/plainjs": "^7.0.4", @@ -7054,9 +7055,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz", - "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.6.tgz", + "integrity": "sha512-BtJZb+hYXGaVJJivpnDoi3JFVn80SHKCiiRUW3kk1SY6UCUy5dWFFSbh+tGi5lHAughzeduMyxbLt3pspvXNSg==", "cpu": [ "arm64" ], @@ -7069,9 +7070,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz", - "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.6.tgz", + "integrity": "sha512-ZHRbGpH6KHarzm6qEeXKSElSXh8dS2DtDPjQt3IMwY8QVk7GbdDYjvV4NgSnDA9huGpGgnyy3tH8i5yHCqVkiQ==", "cpu": [ "x64" ], @@ -7084,9 +7085,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz", - "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.6.tgz", + "integrity": "sha512-O4HqUEe3ZvKshXHcDUXn1OybN4cSZg7ZdwHJMGCXSUEVUqGTJVsOh17smqilIjooP/sIJksgl+1kcf2IWMZWHg==", "cpu": [ "arm64" ], @@ -7099,9 +7100,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz", - "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.6.tgz", + "integrity": "sha512-xUcdhr2hfalG8RDDGSFxQ75yOG894UlmFS4K2M0jLrUhauRBGOtUOxoDVwiIIuZQwZ3Y5hDsazNjdYGB0cQ9yQ==", "cpu": [ "arm64" ], @@ -7114,9 +7115,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz", - "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.6.tgz", + "integrity": "sha512-InosKxw8UMcA/wEib5n2QttwHSKHZHNSbGcMepBM0CTcNwpxWzX32KETmwbhKod3zrS8n1vJ+DuJKbL9ZAB0Ag==", "cpu": [ "x64" ], @@ -7129,9 +7130,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz", - "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.6.tgz", + "integrity": "sha512-d4QXfJmt5pGJ7cG8qwxKSBnO5AXuKAFYxV7qyDRHnUNvY/dgDh+oX292gATpB2AAHgjdHd5ks1wXxIEj6muLUQ==", "cpu": [ "x64" ], @@ -7144,9 +7145,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz", - "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.6.tgz", + "integrity": "sha512-AlgIhk4/G+PzOG1qdF1b05uKTMsuRatFlFzAi5G8RZ9h67CVSSuZSbqGHbJDlcV1tZPxq/d4G0q6qcHDKWf4aQ==", "cpu": [ "arm64" ], @@ -7159,9 +7160,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz", - "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.6.tgz", + "integrity": "sha512-hNukAxq7hu4o5/UjPp5jqoBEtrpCbOmnUqZSKNJG8GrUVzfq0ucdhQFVrHcLRMvQcwqqDh1a5AJN9ORnNDpgBQ==", "cpu": [ "ia32" ], @@ -7174,9 +7175,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz", - "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.6.tgz", + "integrity": "sha512-NANtw+ead1rSDK1jxmzq3TYkl03UNK2KHqUYf1nIhNci6NkeqBD4s1njSzYGIlSHxCK+wSaL8RXZm4v+NF/pMw==", "cpu": [ "x64" ], @@ -36432,7 +36433,8 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "axios": "^1.7.2" + "axios": "^1.7.2", + "lodash": "^4.17.21" }, "devDependencies": { "@akashnetwork/akashjs": "^0.10.0" @@ -36526,141 +36528,6 @@ "peerDependencies": { "react": ">=16.13.1" } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.6.tgz", - "integrity": "sha512-BtJZb+hYXGaVJJivpnDoi3JFVn80SHKCiiRUW3kk1SY6UCUy5dWFFSbh+tGi5lHAughzeduMyxbLt3pspvXNSg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.6.tgz", - "integrity": "sha512-ZHRbGpH6KHarzm6qEeXKSElSXh8dS2DtDPjQt3IMwY8QVk7GbdDYjvV4NgSnDA9huGpGgnyy3tH8i5yHCqVkiQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.6.tgz", - "integrity": "sha512-O4HqUEe3ZvKshXHcDUXn1OybN4cSZg7ZdwHJMGCXSUEVUqGTJVsOh17smqilIjooP/sIJksgl+1kcf2IWMZWHg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.6.tgz", - "integrity": "sha512-xUcdhr2hfalG8RDDGSFxQ75yOG894UlmFS4K2M0jLrUhauRBGOtUOxoDVwiIIuZQwZ3Y5hDsazNjdYGB0cQ9yQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.6.tgz", - "integrity": "sha512-InosKxw8UMcA/wEib5n2QttwHSKHZHNSbGcMepBM0CTcNwpxWzX32KETmwbhKod3zrS8n1vJ+DuJKbL9ZAB0Ag==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.6.tgz", - "integrity": "sha512-d4QXfJmt5pGJ7cG8qwxKSBnO5AXuKAFYxV7qyDRHnUNvY/dgDh+oX292gATpB2AAHgjdHd5ks1wXxIEj6muLUQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.6.tgz", - "integrity": "sha512-AlgIhk4/G+PzOG1qdF1b05uKTMsuRatFlFzAi5G8RZ9h67CVSSuZSbqGHbJDlcV1tZPxq/d4G0q6qcHDKWf4aQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.6.tgz", - "integrity": "sha512-hNukAxq7hu4o5/UjPp5jqoBEtrpCbOmnUqZSKNJG8GrUVzfq0ucdhQFVrHcLRMvQcwqqDh1a5AJN9ORnNDpgBQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.6.tgz", - "integrity": "sha512-NANtw+ead1rSDK1jxmzq3TYkl03UNK2KHqUYf1nIhNci6NkeqBD4s1njSzYGIlSHxCK+wSaL8RXZm4v+NF/pMw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } } } } From dacf32a64281e794a7276319873768213b83f6de Mon Sep 17 00:00:00 2001 From: Maxime Beauchamp <15185355+baktun14@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:52:08 -0400 Subject: [PATCH 09/11] chore: update console FAQ + add amd64 cpu support (#399) --- .../deployments/DeploymentLeaseShell.tsx | 7 +- apps/deploy-web/src/pages/faq/index.tsx | 92 +++++++++---------- packages/network-store/src/network.store.ts | 2 +- 3 files changed, 48 insertions(+), 53 deletions(-) diff --git a/apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx b/apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx index d78e77baf..7c92d7dcc 100644 --- a/apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx +++ b/apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx @@ -283,12 +283,7 @@ export const DeploymentLeaseShell: React.FunctionComponent = ({ leases }) {isConnectionClosed && ( - The connection to your Akash Console Shell was lost. ( - - More Info - - - ) + The connection to your Akash Console Shell was not established or lost. )} diff --git a/apps/deploy-web/src/pages/faq/index.tsx b/apps/deploy-web/src/pages/faq/index.tsx index f7c06cb97..f8a6f618d 100644 --- a/apps/deploy-web/src/pages/faq/index.tsx +++ b/apps/deploy-web/src/pages/faq/index.tsx @@ -6,6 +6,34 @@ import Layout from "@src/components/layout/Layout"; import { Title } from "@src/components/shared/Title"; const FaqEntries = [ + { + anchor: "cpu-support", + title: "Which CPUs are officially supported?", + content: ( + <> +

+ + Only x86_64 processors + {" "} + are officially supported for Akash deployments. This may change in the future and when ARM processors are supported it will be announced and + documented. +

+

+ If you're on MacOS or linux, you can specify the{" "} + + target platform + {" "} + when building your docker image. For example, if you're using a Dockerfile you can use the following command: +

+

+ docker build -t my-image --platform linux/amd64 . +

+ + ) + }, { anchor: "lease-closed", title: "My lease is closed, but the deployment isn't.", @@ -34,36 +62,6 @@ const FaqEntries = [ ) }, - { - anchor: "shell-lost", - title: "Can't access shell: 'The connection to your Akash Console Shell was lost.'", - content: ( - <> -

- There is a{" "} - - known issue - {" "} - where the shell access will stop working if the provider pod gets restarted. Here's two workarounds you can try: -

-
    -
  • - You can try the "UPDATE DEPLOYMENT" button in the "UPDATE" tab of your deployment. Even without changing your SDL, this should temporarily restore - the shell access. -
    - Update Deployment -
  • -
  • - A permanent solution would be to add your own ssh access to your deployment, here is an{" "} - - example SDL - {" "} - with ssh. -
  • -
- - ) - }, { anchor: "shell-arrows-and-completion", title: "Shell: UP arrow and TAB autocompletion does not work", @@ -130,23 +128,25 @@ export default function FaqPage() { Frequently Asked Questions -
    - {FaqEntries.map(entry => ( -
  • - {entry.title} -
  • - ))} -
+
+
    + {FaqEntries.map(entry => ( +
  • + {entry.title} +
  • + ))} +
-
- {FaqEntries.map(entry => ( -
- - {entry.title} - - {entry.content} -
- ))} +
+ {FaqEntries.map(entry => ( +
+ + {entry.title} + + {entry.content} +
+ ))} +
); diff --git a/packages/network-store/src/network.store.ts b/packages/network-store/src/network.store.ts index f919c4a90..6f13aff3f 100644 --- a/packages/network-store/src/network.store.ts +++ b/packages/network-store/src/network.store.ts @@ -105,7 +105,7 @@ export class NetworkStore { } } - private initiateNetworkFromUrlQuery(): Network["id"] { + private initiateNetworkFromUrlQuery(): Network["id"] | undefined { if (typeof window === "undefined") { return; } From ed22ad7181e12f4e30583be2a9c118596146bf14 Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 3 Oct 2024 11:16:52 +0200 Subject: [PATCH 10/11] feat(config): setup doppler env for api --- apps/api/deploy.yml | 13 +------------ apps/api/package.json | 1 + apps/indexer/package.json | 1 + apps/stats-web/package.json | 1 + apps/stats-web/src/hooks/useSelectedNetwork.ts | 0 apps/stats-web/src/lib/constants.ts | 0 apps/stats-web/src/store/networkStore.ts | 0 docker/Dockerfile.node | 11 +++++++++-- packages/network-store/src/network.store.ts | 2 +- 9 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 apps/stats-web/src/hooks/useSelectedNetwork.ts create mode 100644 apps/stats-web/src/lib/constants.ts create mode 100644 apps/stats-web/src/store/networkStore.ts diff --git a/apps/api/deploy.yml b/apps/api/deploy.yml index 9067ad4c4..0f632041c 100644 --- a/apps/api/deploy.yml +++ b/apps/api/deploy.yml @@ -6,19 +6,8 @@ services: image: : depends-on: cloud-sql-proxy env: - - GITHUB_PAT= - - AKASH_SANDBOX_DATABASE_CS= - - USER_DATABASE_CS= - - SECRET_TOKEN= - - NETWORK= - - MASTER_WALLET_MNEMONIC= - - POSTGRES_DB_URI= - - ANONYMOUS_USER_TOKEN_SECRET= - - SENTRY_DSN= + - DOPPLER_TOKEN= - SENTRY_SERVER_NAME= - - DEPLOYMENT_ENV= - - STRIPE_SECRET_KEY= - - STRIPE_WEBHOOK_SECRET= expose: - port: 3080 as: 80 diff --git a/apps/api/package.json b/apps/api/package.json index f6e2f54bf..66f481867 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -19,6 +19,7 @@ "lint": "eslint .", "migrate": "node-pg-migrate", "migration:gen": "drizzle-kit generate", + "prod": "doppler run -- node dist/server.js", "start": "webpack --config webpack.dev.js --watch", "test": "jest --selectProjects unit functional", "test:cov": "jest --selectProjects unit functional --coverage", diff --git a/apps/indexer/package.json b/apps/indexer/package.json index 6b23c4c92..4808c0737 100644 --- a/apps/indexer/package.json +++ b/apps/indexer/package.json @@ -18,6 +18,7 @@ "dev": "npm run start", "format": "prettier --write ./*.{js,json} **/*.{ts,js,json}", "lint": "eslint .", + "prod": "node dist/server.js", "start": "webpack --mode development --config webpack.dev.js --watch", "test": "jest" }, diff --git a/apps/stats-web/package.json b/apps/stats-web/package.json index c9a54267f..2616ebbb7 100644 --- a/apps/stats-web/package.json +++ b/apps/stats-web/package.json @@ -13,6 +13,7 @@ "dependencies": { "@akashnetwork/network-store": "*", "@akashnetwork/ui": "*", + "@akashnetwork/network-store": "*", "@cosmjs/encoding": "^0.32.4", "@json2csv/plainjs": "^7.0.4", "@nivo/line": "^0.87.0", diff --git a/apps/stats-web/src/hooks/useSelectedNetwork.ts b/apps/stats-web/src/hooks/useSelectedNetwork.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/stats-web/src/lib/constants.ts b/apps/stats-web/src/lib/constants.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/stats-web/src/store/networkStore.ts b/apps/stats-web/src/store/networkStore.ts new file mode 100644 index 000000000..e69de29bb diff --git a/docker/Dockerfile.node b/docker/Dockerfile.node index 630ccb489..6c5e38b9d 100644 --- a/docker/Dockerfile.node +++ b/docker/Dockerfile.node @@ -44,11 +44,15 @@ RUN npm ci --workspace $WORKSPACE --omit=dev RUN apk add --no-cache libcap; \ setcap cap_net_bind_service=+ep `readlink -f \`which node\`` +RUN wget -q -t3 'https://packages.doppler.com/public/cli/rsa.8004D9FF50437357.key' -O /etc/apk/keys/cli@doppler-8004D9FF50437357.rsa.pub && \ + echo 'https://packages.doppler.com/public/cli/alpine/any-version/main' | tee -a /etc/apk/repositories && \ + apk add doppler + USER $APP_USER WORKDIR /app/$WORKSPACE -CMD ["node", "dist/server.js"] +CMD ["npm", "run", "prod"] FROM production AS production-nginx @@ -62,4 +66,7 @@ RUN apk add --no-cache libcap nginx openssl \ COPY $WORKSPACE/nginx.conf /etc/nginx/nginx.conf -CMD sed -i "s/127.0.0.1/$(hostname -i)/" /etc/nginx/nginx.conf && sed -i "s/:3000/:$PORT/" /etc/nginx/nginx.conf && nginx && node dist/server.js \ No newline at end of file +ARG PORT=3000 +ENV PORT=${PORT} + +CMD sed -i "s/127.0.0.1/$(hostname -i)/" /etc/nginx/nginx.conf && sed -i "s/:3000/:$PORT/" /etc/nginx/nginx.conf && nginx && npm run prod \ No newline at end of file diff --git a/packages/network-store/src/network.store.ts b/packages/network-store/src/network.store.ts index 6f13aff3f..2d65b61b2 100644 --- a/packages/network-store/src/network.store.ts +++ b/packages/network-store/src/network.store.ts @@ -105,7 +105,7 @@ export class NetworkStore { } } - private initiateNetworkFromUrlQuery(): Network["id"] | undefined { + private initiateNetworkFromUrlQuery(): void { if (typeof window === "undefined") { return; } From 2e9f0f277b8b4924c894d1e68e6b363efb6a1f81 Mon Sep 17 00:00:00 2001 From: dharamveergit Date: Thu, 10 Oct 2024 17:25:43 +0530 Subject: [PATCH 11/11] fix: useMemo in envVArUpdater --- .../remote-deploy/RemoteRepositoryDeployManager.tsx | 4 ++-- apps/deploy-web/src/components/remote-deploy/Repos.tsx | 8 ++------ .../RemoteBuildInstallConfig.tsx | 4 ++-- .../remote-deploy/update/RemoteDeployUpdate.tsx | 4 ++-- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/deploy-web/src/components/remote-deploy/RemoteRepositoryDeployManager.tsx b/apps/deploy-web/src/components/remote-deploy/RemoteRepositoryDeployManager.tsx index 368fdce0f..75eae49c2 100644 --- a/apps/deploy-web/src/components/remote-deploy/RemoteRepositoryDeployManager.tsx +++ b/apps/deploy-web/src/components/remote-deploy/RemoteRepositoryDeployManager.tsx @@ -1,4 +1,4 @@ -import { Dispatch, useEffect, useState } from "react"; +import { Dispatch, useEffect, useMemo, useState } from "react"; import { Control, UseFormSetValue } from "react-hook-form"; import { Button, Spinner, Tabs, TabsContent, TabsList, TabsTrigger } from "@akashnetwork/ui/components"; import { Bitbucket, Github as GitIcon, GitlabFull } from "iconoir-react"; @@ -53,7 +53,7 @@ const RemoteRepositoryDeployManager = ({ const shouldResetValue = isRepoUrlDefault(services?.[0]?.env || []); - const envVarUpdater = new EnvVarUpdater(services); + const envVarUpdater = useMemo(() => new EnvVarUpdater(services), [services]); const { reLoginWithGithub, loginWithGithub } = new GitHubService(); diff --git a/apps/deploy-web/src/components/remote-deploy/Repos.tsx b/apps/deploy-web/src/components/remote-deploy/Repos.tsx index 5c50684b7..8894c304e 100644 --- a/apps/deploy-web/src/components/remote-deploy/Repos.tsx +++ b/apps/deploy-web/src/components/remote-deploy/Repos.tsx @@ -1,4 +1,4 @@ -import { Dispatch, useEffect, useState } from "react"; +import { Dispatch, useEffect, useMemo, useState } from "react"; import { UseFormSetValue } from "react-hook-form"; import { Button, @@ -64,10 +64,8 @@ const Repos = ({ const [directory, setDirectory] = useState(null); const [open, setOpen] = useState(false); const [accounts, setAccounts] = useState([]); - const envVarUpdater = new EnvVarUpdater(services); const repo = repos?.find(r => r.html_url === currentRepoUrl); const currentFolder = currentServiceEnv?.find(e => e.key === protectedEnvironmentVariables.FRONTEND_FOLDER); - const { currentFramework, isLoading: frameworkLoading } = useRemoteDeployFramework({ currentRepoUrl, currentBranchName, @@ -75,20 +73,18 @@ const Repos = ({ subFolder: currentFolder?.value, setCpus: (cpus: number) => setValue("services.0.profile.cpu", +cpus > 2 ? +cpus : 2) }); - const { isLoading: isGettingDirectory, isFetching: isGithubLoading } = useSrcFolders(setFolders, formatUrlWithoutInitialPath(currentRepoUrl)); const { isLoading: isGettingDirectoryBit, isFetching: isBitLoading } = useBitSrcFolders( setFolders, formatUrlWithoutInitialPath(currentRepoUrl), currentBranchName ); - const { isLoading: isGettingDirectoryGitlab, isFetching: isGitlabLoading } = useGitlabSrcFolders( setFolders, currentServiceEnv?.find(e => e.key === protectedEnvironmentVariables.GITLAB_PROJECT_ID)?.value ); - const isLoadingDirectories = isGithubLoading || isGitlabLoading || isBitLoading || isGettingDirectory || isGettingDirectoryBit || isGettingDirectoryGitlab; + const envVarUpdater = useMemo(() => new EnvVarUpdater(services), [services]); useEffect(() => { if (type === "github") { diff --git a/apps/deploy-web/src/components/remote-deploy/deployment-configurations/RemoteBuildInstallConfig.tsx b/apps/deploy-web/src/components/remote-deploy/deployment-configurations/RemoteBuildInstallConfig.tsx index 4136dfe5b..e3385987c 100644 --- a/apps/deploy-web/src/components/remote-deploy/deployment-configurations/RemoteBuildInstallConfig.tsx +++ b/apps/deploy-web/src/components/remote-deploy/deployment-configurations/RemoteBuildInstallConfig.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { UseFormSetValue } from "react-hook-form"; import { Card, CardContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Label, Separator } from "@akashnetwork/ui/components"; import { cn } from "@akashnetwork/ui/utils"; @@ -12,7 +12,7 @@ import BoxTextInput from "../BoxTextInput"; const RemoteBuildInstallConfig = ({ services, setValue }: { services: ServiceType[]; setValue: UseFormSetValue }) => { const [expanded, setExpanded] = useState(false); const currentService = services[0]; - const envVarUpdater = new EnvVarUpdater(services); + const envVarUpdater = useMemo(() => new EnvVarUpdater(services), [services]); return ( (false); const { control, watch, setValue } = useForm({ defaultValues: { services: [defaultService] } }); const { fields: services } = useFieldArray({ control, name: "services", keyName: "id" }); - const envVarUpdater = new EnvVarUpdater(services); const { getTemplateById } = useTemplates(); const remoteDeployTemplate = getTemplateById(CI_CD_TEMPLATE_ID); + const envVarUpdater = useMemo(() => new EnvVarUpdater(services), [services]); useEffect(() => { const { unsubscribe }: any = watch(data => {