From 937dabb1ee603236bc5588bb0fd3d95064a7f750 Mon Sep 17 00:00:00 2001 From: schmanu Date: Mon, 13 Nov 2023 12:13:53 +0100 Subject: [PATCH 01/11] fix: different configs for staging and prod --- src/services/mpc/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/mpc/config.ts b/src/services/mpc/config.ts index 5a2f4aa729..17dce21cc2 100644 --- a/src/services/mpc/config.ts +++ b/src/services/mpc/config.ts @@ -32,7 +32,7 @@ export const SOCIAL_WALLET_OPTIONS: any = (() => { const SOCIAL_WALLET_OPTIONS_STAGING = process.env.NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_STAGING || '' try { - return JSON.parse(IS_PRODUCTION ? SOCIAL_WALLET_OPTIONS_PRODUCTION : SOCIAL_WALLET_OPTIONS_PRODUCTION) + return JSON.parse(IS_PRODUCTION ? SOCIAL_WALLET_OPTIONS_PRODUCTION : SOCIAL_WALLET_OPTIONS_STAGING) } catch (error) { console.error('Error parsing SOCIAL_WALLET_OPTIONS', error) return {} From f3fc362f7cc196d58dbc3c23337e24927fc82a25 Mon Sep 17 00:00:00 2001 From: katspaugh <381895+katspaugh@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:44:56 +0100 Subject: [PATCH 02/11] Fix: prefix switch for receive QR (#2795) --- .../balances/AssetsTable/NoAssets.tsx | 76 +++++++++++++++++++ src/components/balances/AssetsTable/index.tsx | 61 +-------------- 2 files changed, 78 insertions(+), 59 deletions(-) create mode 100644 src/components/balances/AssetsTable/NoAssets.tsx diff --git a/src/components/balances/AssetsTable/NoAssets.tsx b/src/components/balances/AssetsTable/NoAssets.tsx new file mode 100644 index 0000000000..ebf337c6f6 --- /dev/null +++ b/src/components/balances/AssetsTable/NoAssets.tsx @@ -0,0 +1,76 @@ +import Link from 'next/link' +import { useRouter } from 'next/router' +import { Box, Button, FormControlLabel, Grid, Paper, Switch, Typography } from '@mui/material' +import EthHashInfo from '@/components/common/EthHashInfo' +import QRCode from '@/components/common/QRCode' +import { AppRoutes } from '@/config/routes' +import { useRemoteSafeApps } from '@/hooks/safe-apps/useRemoteSafeApps' +import { useCurrentChain } from '@/hooks/useChains' +import useSafeAddress from '@/hooks/useSafeAddress' +import { useAppDispatch, useAppSelector } from '@/store' +import { selectSettings, setQrShortName } from '@/store/settingsSlice' +import AddIcon from '@mui/icons-material/Add' + +const NoAssets = () => { + const router = useRouter() + const safeAddress = useSafeAddress() + const chain = useCurrentChain() + const dispatch = useAppDispatch() + const settings = useAppSelector(selectSettings) + const qrPrefix = settings.shortName.qr ? `${chain?.shortName}:` : '' + const qrCode = `${qrPrefix}${safeAddress}` + const [apps] = useRemoteSafeApps() + + // @FIXME: use tags instead of name + const rampSafeApp = apps?.find((app) => app.name === 'Ramp Network') + + return ( + + + +
+ + + +
+ + dispatch(setQrShortName(e.target.checked))} /> + } + label={<>QR code with chain prefix} + /> +
+ + + + Add funds to get started + + + + Add funds directly from your bank account or copy your address to send tokens from a different account. + + + + + + + {rampSafeApp && ( + + + + + + )} + +
+
+ ) +} + +export default NoAssets diff --git a/src/components/balances/AssetsTable/index.tsx b/src/components/balances/AssetsTable/index.tsx index 599c8c2704..57c0a28c16 100644 --- a/src/components/balances/AssetsTable/index.tsx +++ b/src/components/balances/AssetsTable/index.tsx @@ -1,15 +1,5 @@ -import EthHashInfo from '@/components/common/EthHashInfo' -import QRCode from '@/components/common/QRCode' -import { AppRoutes } from '@/config/routes' -import { useRemoteSafeApps } from '@/hooks/safe-apps/useRemoteSafeApps' -import { useCurrentChain } from '@/hooks/useChains' -import useSafeAddress from '@/hooks/useSafeAddress' -import { useAppSelector } from '@/store' -import { selectSettings } from '@/store/settingsSlice' -import Link from 'next/link' -import { useRouter } from 'next/router' import { type ReactElement, useMemo, useContext } from 'react' -import { Button, Tooltip, Typography, SvgIcon, IconButton, Box, Checkbox, Skeleton, Paper, Grid } from '@mui/material' +import { Button, Tooltip, Typography, SvgIcon, IconButton, Box, Checkbox, Skeleton } from '@mui/material' import type { TokenInfo } from '@safe-global/safe-gateway-typescript-sdk' import { TokenType } from '@safe-global/safe-gateway-typescript-sdk' import css from './styles.module.css' @@ -30,7 +20,7 @@ import CheckWallet from '@/components/common/CheckWallet' import useSpendingLimit from '@/hooks/useSpendingLimit' import { TxModalContext } from '@/components/tx-flow' import TokenTransferFlow from '@/components/tx-flow/flows/TokenTransfer' -import AddIcon from '@mui/icons-material/Add' +import NoAssets from './NoAssets' const skeletonCells: EnhancedTableProps['rows'][0]['cells'] = { asset: { @@ -271,51 +261,4 @@ const AssetsTable = ({ ) } -const NoAssets = () => { - const router = useRouter() - const safeAddress = useSafeAddress() - const chain = useCurrentChain() - const settings = useAppSelector(selectSettings) - const qrPrefix = settings.shortName.qr ? `${chain?.shortName}:` : '' - const qrCode = `${qrPrefix}${safeAddress}` - const [apps] = useRemoteSafeApps() - - const rampSafeApp = apps?.find((app) => app.name === 'Ramp Network') - - return ( - - - - - - - - - - Add funds to get started - - - Add funds directly from your bank account or copy your address to send tokens from a different account. - - - - - {rampSafeApp && ( - - - - - - )} - - - - ) -} - export default AssetsTable From 8419d23da3720e2c53f21f82a94c56205324d795 Mon Sep 17 00:00:00 2001 From: Manuel Gellfart Date: Mon, 13 Nov 2023 15:51:48 +0100 Subject: [PATCH 03/11] fix: allow execution of web assembly (#2797) * fix: allow execution of web assembly * fix: CSP string --- src/config/securityHeaders.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/securityHeaders.ts b/src/config/securityHeaders.ts index 69dd425090..8d3faa3bb1 100644 --- a/src/config/securityHeaders.ts +++ b/src/config/securityHeaders.ts @@ -15,7 +15,7 @@ export const ContentSecurityPolicy = ` script-src 'self' https://www.google-analytics.com https://ssl.google-analytics.com 'unsafe-inline' https://*.getbeamer.com https://www.googletagmanager.com https://*.ingest.sentry.io https://sentry.io ${ !IS_PRODUCTION || /* TODO: remove after moving cypress to görli and testing in staging again!! */ CYPRESS_MNEMONIC ? "'unsafe-eval'" - : '' + : "'wasm-unsafe-eval'" }; frame-src *; style-src 'self' 'unsafe-inline' https://*.getbeamer.com https://*.googleapis.com; From c8752b58731a15107a15c099a8948ce6cf9baffe Mon Sep 17 00:00:00 2001 From: katspaugh Date: Mon, 13 Nov 2023 15:52:05 +0100 Subject: [PATCH 04/11] 1.22.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26ac24be3c..60669cabad 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "homepage": "https://github.com/safe-global/safe-wallet-web", "license": "GPL-3.0", "type": "module", - "version": "1.22.0", + "version": "1.22.1", "scripts": { "dev": "next dev", "start": "next dev", From ced3211d6d5552e7c9087a476d6cd9f0f0db82ec Mon Sep 17 00:00:00 2001 From: katspaugh <381895+katspaugh@users.noreply.github.com> Date: Mon, 13 Nov 2023 16:39:07 +0100 Subject: [PATCH 05/11] Fix: revert relaying message (#2799) --- package.json | 2 +- .../tx/ExecutionMethodSelector/index.tsx | 2 +- .../tx/SignOrExecuteForm/ExecuteForm.tsx | 25 +++--- src/components/tx/SponsoredBy/index.tsx | 87 +++++++------------ src/hooks/useWalletCanRelay.ts | 8 +- 5 files changed, 44 insertions(+), 80 deletions(-) diff --git a/package.json b/package.json index 60669cabad..329f71c72e 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "homepage": "https://github.com/safe-global/safe-wallet-web", "license": "GPL-3.0", "type": "module", - "version": "1.22.1", + "version": "1.22.2", "scripts": { "dev": "next dev", "start": "next dev", diff --git a/src/components/tx/ExecutionMethodSelector/index.tsx b/src/components/tx/ExecutionMethodSelector/index.tsx index baae6e7855..95e56b9d4a 100644 --- a/src/components/tx/ExecutionMethodSelector/index.tsx +++ b/src/components/tx/ExecutionMethodSelector/index.tsx @@ -71,7 +71,7 @@ export const ExecutionMethodSelector = ({ - + {shouldRelay && relays ? : null} ) } diff --git a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx index 628c5877f9..72ae840fc6 100644 --- a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx +++ b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx @@ -12,6 +12,7 @@ import { useIsExecutionLoop, useTxActions } from './hooks' import { useRelaysBySafe } from '@/hooks/useRemainingRelays' import useWalletCanRelay from '@/hooks/useWalletCanRelay' import { ExecutionMethod, ExecutionMethodSelector } from '../ExecutionMethodSelector' +import { hasRemainingRelays } from '@/utils/relaying' import type { SignOrExecuteProps } from '.' import type { SafeTransaction } from '@safe-global/safe-core-sdk-types' import { TxModalContext } from '@/components/tx-flow' @@ -52,13 +53,15 @@ const ExecuteForm = ({ // Check that the transaction is executable const isExecutionLoop = useIsExecutionLoop() - // SC wallets can relay fully signed transactions - const [canWalletRelay] = useWalletCanRelay(safeTx) - // We default to relay + // We default to relay, but the option is only shown if we canRelay const [executionMethod, setExecutionMethod] = useState(ExecutionMethod.RELAY) + + // SC wallets can relay fully signed transactions + const [walletCanRelay] = useWalletCanRelay(safeTx) + // The transaction can/will be relayed - const willRelay = executionMethod === ExecutionMethod.RELAY - const hasRelays = !!relays?.remaining + const canRelay = walletCanRelay && hasRemainingRelays(relays) + const willRelay = canRelay && executionMethod === ExecutionMethod.RELAY // Estimate gas limit const { gasLimit, gasLimitError } = useGasLimit(safeTx) @@ -99,18 +102,12 @@ const ExecuteForm = ({ const cannotPropose = !isOwner && !onlyExecute const submitDisabled = - !safeTx || - !isSubmittable || - disableSubmit || - isValidExecutionLoading || - isExecutionLoop || - cannotPropose || - (willRelay && !hasRelays) + !safeTx || !isSubmittable || disableSubmit || isValidExecutionLoading || isExecutionLoop || cannotPropose return ( <>
-
+
- {canWalletRelay && ( + {canRelay && (
{ +const SponsoredBy = ({ relays, tooltip }: { relays: RelayResponse; tooltip?: string }) => { const chain = useCurrentChain() return ( - - {shouldRelay ? ( -
- - - Sponsored by - - - {chain?.chainName} - - {chain?.chainName} - - - {tooltip ? ( - - - - - - ) : null} - - - - Transactions per hour:{' '} - - {relays?.remaining ?? 0} of {relays?.limit ?? 0} - - {relays && !relays.remaining && ( - - {' '} - — will reset in the next hour - - )} - -
- ) : ( -
+
+ - Pay gas from the connected wallet + Sponsored by - - - Please make sure your wallet has sufficient funds. + {chain?.chainName} + + {chain?.chainName} -
- )} + {tooltip ? ( + + + + + + ) : null} + + + + Transactions per hour:{' '} + + {relays.remaining} of {relays.limit} + + +
) } diff --git a/src/hooks/useWalletCanRelay.ts b/src/hooks/useWalletCanRelay.ts index d451855b3c..e7261e0226 100644 --- a/src/hooks/useWalletCanRelay.ts +++ b/src/hooks/useWalletCanRelay.ts @@ -4,18 +4,14 @@ import useWallet from '@/hooks/wallets/useWallet' import { isSmartContractWallet } from '@/utils/wallets' import { Errors, logError } from '@/services/exceptions' import { type SafeTransaction } from '@safe-global/safe-core-sdk-types' -import { FEATURES, hasFeature } from '@/utils/chains' -import { useCurrentChain } from './useChains' const useWalletCanRelay = (tx: SafeTransaction | undefined) => { const { safe } = useSafeInfo() const wallet = useWallet() - const chain = useCurrentChain() - const isFeatureEnabled = chain && hasFeature(chain, FEATURES.RELAYING) const hasEnoughSignatures = tx && tx.signatures.size >= safe.threshold return useAsync(() => { - if (!isFeatureEnabled || !tx || !wallet) return + if (!tx || !wallet) return return isSmartContractWallet(wallet) .then((isSCWallet) => { @@ -27,7 +23,7 @@ const useWalletCanRelay = (tx: SafeTransaction | undefined) => { logError(Errors._106, err.message) return false }) - }, [isFeatureEnabled, hasEnoughSignatures, tx, wallet]) + }, [hasEnoughSignatures, tx, wallet]) } export default useWalletCanRelay From b356d75cd4eba5af0b5aedefd7d8fc9b50869b3b Mon Sep 17 00:00:00 2001 From: Michael <30682308+mike10ca@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:30:32 +0100 Subject: [PATCH 06/11] Tests: Add test IDs and modify NFT tests (#2804) * Add test IDs amd modify nft tests --- cypress/e2e/pages/main.page.js | 1 + cypress/e2e/pages/nfts.pages.js | 76 +++++++++++-------- cypress/e2e/safe-apps/tx-builder.spec.cy.js | 2 +- cypress/e2e/smoke/nfts.cy.js | 10 +-- src/components/common/ModalDialog/index.tsx | 4 +- src/components/nfts/NftGrid/index.tsx | 18 ++++- src/components/nfts/NftSendForm/index.tsx | 1 + .../tx-flow/common/TxLayout/index.tsx | 17 ++++- .../flows/NftTransfer/SendNftBatch.tsx | 21 ++++- .../tx/SignOrExecuteForm/SignForm.tsx | 2 +- 10 files changed, 105 insertions(+), 47 deletions(-) diff --git a/cypress/e2e/pages/main.page.js b/cypress/e2e/pages/main.page.js index 438797b93c..2c6df5a423 100644 --- a/cypress/e2e/pages/main.page.js +++ b/cypress/e2e/pages/main.page.js @@ -1,6 +1,7 @@ import * as constants from '../../support/constants' const acceptSelection = 'Accept selection' +export const modalDialogCloseBtn = '[data-testid="modal-dialog-close-btn"]' export function clickOnSideMenuItem(item) { cy.get('p').contains(item).click() diff --git a/cypress/e2e/pages/nfts.pages.js b/cypress/e2e/pages/nfts.pages.js index 85775098cb..82796786f6 100644 --- a/cypress/e2e/pages/nfts.pages.js +++ b/cypress/e2e/pages/nfts.pages.js @@ -1,8 +1,22 @@ import * as constants from '../../support/constants' +import * as main from '../pages/main.page' -const nftModal = 'div[role="dialog"]' -const nftModalCloseBtn = 'button[aria-label="close"]' +const nftModalTitle = '[data-testid="modal-title"]' +const nftModal = '[data-testid="modal-view"]' + +const nftModalCloseBtn = main.modalDialogCloseBtn const recipientInput = 'input[name="recipient"]' +const nftsRow = '[data-testid^="nfts-table-row"]' +const inactiveNftIcon = '[data-testid="nft-icon-border"]' +const activeNftIcon = '[data-testid="nft-icon-primary"]' +const nftCheckBox = (index) => `[data-testid="nft-checkbox-${index}"] > input` +const activeSendNFTBtn = '[data-testid="nft-send-btn-false"]' +const modalTitle = '[data-testid="modal-title"]' +const modalHeader = '[data-testid="modal-header"]' +const modalSelectedNFTs = '[data-testid="selected-nfts"]' +const nftItemList = '[data-testid="nft-item-list"]' +const nftItemNane = '[data-testid="nft-item-name"]' +const signBtn = '[data-testid="sign-btn"]' const noneNFTSelected = '0 NFTs selected' const sendNFTStr = 'Send NFTs' @@ -19,7 +33,8 @@ export function clickOnNftsTab() { cy.get('p').contains('NFTs').click() } function verifyTableRows(number) { - cy.get('tbody tr').should('have.length', number) + cy.scrollTo('bottom').wait(500) + cy.get(nftsRow).should('have.length.at.least', number) } export function verifyNFTNumber(number) { @@ -27,44 +42,48 @@ export function verifyNFTNumber(number) { } export function verifyDataInTable(name, address, tokenID) { - cy.get('tbody tr:first-child').contains('td:first-child', name) - cy.get('tbody tr:first-child').contains('td:first-child', address) - cy.get('tbody tr:first-child').contains('td:nth-child(2)', tokenID) + cy.get(nftsRow).contains(name) + cy.get(nftsRow).contains(address) + cy.get(nftsRow).contains(tokenID) } -export function openNFT(index) { - cy.get('tbody').within(() => { - cy.get('tr').eq(index).click() - }) +export function waitForNftItems(count) { + cy.get(nftsRow).should('have.length.at.least', count) +} + +export function openActiveNFT(index) { + cy.get(activeNftIcon).eq(index).click() } export function verifyNameInNFTModal(name) { - cy.get(nftModal).contains(name) + cy.get(nftModalTitle).contains(name) } export function verifySelectedNetwrokSepolia() { - cy.get(nftModal).contains(constants.networks.sepolia) + cy.get(nftModal).within(() => { + cy.get(nftModalTitle).contains(constants.networks.sepolia) + }) } export function verifyNFTModalLink(link) { - cy.get(nftModal).contains(`a[href="${link}"]`, 'View on OpenSea') + cy.get(nftModalTitle).contains(`a[href="${link}"]`, 'View on OpenSea') } export function closeNFTModal() { cy.get(nftModalCloseBtn).click() - cy.get(nftModal).should('not.exist') + cy.get(nftModalTitle).should('not.exist') } -export function clickOn6thNFT() { - cy.get('tbody tr:nth-child(6) td:nth-child(2)').click() +export function clickOnInactiveNFT() { + cy.get(inactiveNftIcon).eq(0).click() } export function verifyNFTModalDoesNotExist() { - cy.get(nftModal).should('not.exist') + cy.get(nftModalTitle).should('not.exist') } export function selectNFTs(numberOfNFTs) { for (let i = 1; i <= numberOfNFTs; i++) { - cy.get(`tbody tr:nth-child(${i}) input[type="checkbox"]`).click() + cy.get(nftCheckBox(i)).click() cy.contains(`${i} NFT${i > 1 ? 's' : ''} selected`) } cy.contains('button', `Send ${numberOfNFTs} NFT${numberOfNFTs > 1 ? 's' : ''}`) @@ -73,8 +92,8 @@ export function selectNFTs(numberOfNFTs) { export function deselectNFTs(checkboxIndexes, checkedItems) { let total = checkedItems - checkboxIndexes.length - checkboxIndexes.forEach((index) => { - cy.get(`tbody tr:nth-child(${index}) input[type="checkbox"]`).uncheck() + checkboxIndexes.forEach((i) => { + cy.get(nftCheckBox(i)).uncheck() }) cy.contains(`${total} NFT${total !== 1 ? 's' : ''} selected`) @@ -88,14 +107,12 @@ export function verifyInitialNFTData() { cy.contains('button[disabled]', 'Send') } -export function sendNFT(numberOfCheckedNFTs) { - cy.contains('button', `Send ${numberOfCheckedNFTs} NFT${numberOfCheckedNFTs !== 1 ? 's' : ''}`).click() +export function sendNFT() { + cy.get(activeSendNFTBtn).click() } export function verifyNFTModalData() { - cy.contains(sendNFTStr) - cy.contains(recipientAddressStr) - cy.contains(selectedNFTStr) + main.verifyElementsExist([modalTitle, modalHeader, modalSelectedNFTs]) } export function typeRecipientAddress(address) { @@ -107,11 +124,10 @@ export function clikOnNextBtn() { } export function verifyReviewModalData(NFTcount) { - cy.contains(sendStr) - cy.contains(toStr) - cy.wait(1000) - cy.get(`b:contains(${transferFromStr})`).should('have.length', NFTcount) - cy.contains('button:not([disabled])', signBtnStr) + main.verifyElementsExist([nftItemList]) + main.verifyElementsCount(nftItemNane, NFTcount) + cy.get(signBtn).should('not.be.disabled') + if (NFTcount > 1) { const numbersArr = Array.from({ length: NFTcount }, (_, index) => index + 1) numbersArr.forEach((number) => { diff --git a/cypress/e2e/safe-apps/tx-builder.spec.cy.js b/cypress/e2e/safe-apps/tx-builder.spec.cy.js index da1bd43e40..057d12a217 100644 --- a/cypress/e2e/safe-apps/tx-builder.spec.cy.js +++ b/cypress/e2e/safe-apps/tx-builder.spec.cy.js @@ -147,7 +147,7 @@ describe('Transaction Builder tests', { defaultCommandTimeout: 20000 }, () => { getBody().findByText(safeapps.sendBatchStr).click() }) cy.get('p').contains('1').should('exist') - cy.get('p').contains('2').should('be.visible') + cy.get('p').contains('2').should('exist') }) it('Verify a batch cannot be created with invalid address', () => { diff --git a/cypress/e2e/smoke/nfts.cy.js b/cypress/e2e/smoke/nfts.cy.js index 01680d3f72..4a39e1a545 100644 --- a/cypress/e2e/smoke/nfts.cy.js +++ b/cypress/e2e/smoke/nfts.cy.js @@ -11,11 +11,11 @@ describe('NFTs tests', () => { cy.clearLocalStorage() cy.visit(constants.balanceNftsUrl + constants.SEPOLIA_TEST_SAFE_5) main.acceptCookies() - nfts.clickOnNftsTab() + nfts.waitForNftItems(2) }) it('Verify that NFTs exist in the table', () => { - nfts.verifyNFTNumber(20) + nfts.verifyNFTNumber(10) }) it('Verify NFT row contains data', () => { @@ -23,14 +23,14 @@ describe('NFTs tests', () => { }) it('Verify NFT preview window can be opened', () => { - nfts.openNFT(0) + nfts.openActiveNFT(0) nfts.verifyNameInNFTModal(nftsTokenID) nfts.verifySelectedNetwrokSepolia() nfts.closeNFTModal() }) it('Verify NFT open does not open if no NFT exits', () => { - nfts.clickOn6thNFT() + nfts.clickOnInactiveNFT() nfts.verifyNFTModalDoesNotExist() }) @@ -38,7 +38,7 @@ describe('NFTs tests', () => { nfts.verifyInitialNFTData() nfts.selectNFTs(3) nfts.deselectNFTs([2], 3) - nfts.sendNFT(2) + nfts.sendNFT() nfts.verifyNFTModalData() nfts.typeRecipientAddress(constants.SEPOLIA_TEST_SAFE_4) nfts.clikOnNextBtn() diff --git a/src/components/common/ModalDialog/index.tsx b/src/components/common/ModalDialog/index.tsx index cede7fe2cf..c9d32eafe6 100644 --- a/src/components/common/ModalDialog/index.tsx +++ b/src/components/common/ModalDialog/index.tsx @@ -20,12 +20,13 @@ interface DialogTitleProps { export const ModalDialogTitle = ({ children, onClose, hideChainIndicator = false, ...other }: DialogTitleProps) => { return ( - + {children} {!hideChainIndicator && } {onClose ? ( { onClose(e, 'backdropClick') @@ -56,6 +57,7 @@ const ModalDialog = ({ return ( e.stopPropagation() const NftIndicator = ({ color }: { color: SvgIconProps['color'] }) => ( - + ) const activeNftIcon = @@ -191,7 +199,7 @@ const NftGrid = ({ const sx = item.imageUri ? { cursor: 'pointer' } : undefined return ( - + {/* Collection name */} @@ -233,7 +241,11 @@ const NftGrid = ({ {/* Checkbox */} - onCheckboxClick(e, item)} /> + onCheckboxClick(e, item)} + /> {/* Insert the children at the end of the table */} {index === filteredNfts.length - 1 && children} diff --git a/src/components/nfts/NftSendForm/index.tsx b/src/components/nfts/NftSendForm/index.tsx index edfb4f5735..9665dcd4e3 100644 --- a/src/components/nfts/NftSendForm/index.tsx +++ b/src/components/nfts/NftSendForm/index.tsx @@ -32,6 +32,7 @@ const NftSendForm = ({ selectedNfts }: NftSendFormProps): ReactElement => { {(isOk) => ( )} diff --git a/src/components/tx-flow/flows/NftTransfer/SendNftBatch.tsx b/src/components/tx-flow/flows/NftTransfer/SendNftBatch.tsx index 3aeee4fab7..b058444f56 100644 --- a/src/components/tx-flow/flows/NftTransfer/SendNftBatch.tsx +++ b/src/components/tx-flow/flows/NftTransfer/SendNftBatch.tsx @@ -37,7 +37,14 @@ const NftItem = ({ image, name, description }: { image: string; name: string; de - + {name} @@ -59,7 +66,15 @@ const NftItem = ({ image, name, description }: { image: string; name: string; de export const NftItems = ({ tokens }: { tokens: SafeCollectibleResponse[] }) => { return ( - + {tokens.map((token) => ( { )} - + Selected NFTs diff --git a/src/components/tx/SignOrExecuteForm/SignForm.tsx b/src/components/tx/SignOrExecuteForm/SignForm.tsx index 03cf9cbaff..410254da8e 100644 --- a/src/components/tx/SignOrExecuteForm/SignForm.tsx +++ b/src/components/tx/SignOrExecuteForm/SignForm.tsx @@ -103,7 +103,7 @@ const SignForm = ({ {/* Submit button */} {(isOk) => ( - )} From 01774c6f12f9a4a15b767b10ed0d66b96a61fd53 Mon Sep 17 00:00:00 2001 From: Franco Venica Date: Tue, 14 Nov 2023 09:24:30 -0300 Subject: [PATCH 07/11] changed status for isSumittable --- src/components/tx/SignOrExecuteForm/ExecuteForm.tsx | 4 ++-- src/components/tx/SignOrExecuteForm/SignForm.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx index 2cb42585b5..e0afd40a59 100644 --- a/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx +++ b/src/components/tx/SignOrExecuteForm/ExecuteForm.tsx @@ -159,8 +159,8 @@ const ExecuteForm = ({ {/* Submit button */} {(isOk) => ( - )} diff --git a/src/components/tx/SignOrExecuteForm/SignForm.tsx b/src/components/tx/SignOrExecuteForm/SignForm.tsx index bfea932d69..208427be3b 100644 --- a/src/components/tx/SignOrExecuteForm/SignForm.tsx +++ b/src/components/tx/SignOrExecuteForm/SignForm.tsx @@ -103,8 +103,8 @@ const SignForm = ({ {/* Submit button */} {(isOk) => ( - )} From 34f1baeabd213db0cf877c9724f7d6d1986d17a2 Mon Sep 17 00:00:00 2001 From: Usame Algan <5880855+usame-algan@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:49:35 +0100 Subject: [PATCH 08/11] chore: Analyze NextJS bundle size action (#2803) * chore: Analyze NextJS bundle size action * fix: Remove redundant caching * fix: Remove working directory --- .github/workflows/nextjs_bundle_analysis.yml | 98 ++++++++++++++++++++ package.json | 6 ++ 2 files changed, 104 insertions(+) create mode 100644 .github/workflows/nextjs_bundle_analysis.yml diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml new file mode 100644 index 0000000000..2e9672b0df --- /dev/null +++ b/.github/workflows/nextjs_bundle_analysis.yml @@ -0,0 +1,98 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: 'Next.js Bundle Analysis' + +on: + pull_request: + push: + branches: + - dev + +permissions: + contents: read # for checkout repository + actions: read # for fetching base branch bundle stats + pull-requests: write # for comments + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + uses: ./.github/workflows/yarn + + - name: Build next.js app + uses: ./.github/workflows/build + with: + secrets: ${{ toJSON(secrets) }} + + # Here's the first place where next-bundle-analysis' own script is used + # This step pulls the raw bundle stats for the current bundle + - name: Analyze bundle + run: npx -p nextjs-bundle-analysis report + + - name: Upload bundle + uses: actions/upload-artifact@v3 + with: + name: bundle + path: .next/analyze/__bundle_analysis.json + + - name: Download base branch bundle stats + uses: dawidd6/action-download-artifact@v2 + if: success() && github.event.number + with: + workflow: nextjs_bundle_analysis.yml + branch: ${{ github.event.pull_request.base.ref }} + path: .next/analyze/base + + # And here's the second place - this runs after we have both the current and + # base branch bundle stats, and will compare them to determine what changed. + # There are two configurable arguments that come from package.json: + # + # - budget: optional, set a budget (bytes) against which size changes are measured + # it's set to 350kb here by default, as informed by the following piece: + # https://infrequently.org/2021/03/the-performance-inequality-gap/ + # + # - red-status-percentage: sets the percent size increase where you get a red + # status indicator, defaults to 20% + # + # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` + # entry in your package.json file. + - name: Compare with base branch bundle + if: success() && github.event.number + run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare + + - name: Get Comment Body + id: get-comment-body + if: success() && github.event.number + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings + run: | + echo "body<> $GITHUB_OUTPUT + echo "$(cat .next/analyze/__bundle_analysis_comment.txt)" >> $GITHUB_OUTPUT + echo EOF >> $GITHUB_OUTPUT + + - name: Find Comment + uses: peter-evans/find-comment@v2 + if: success() && github.event.number + id: fc + with: + issue-number: ${{ github.event.number }} + body-includes: '' + + - name: Create Comment + uses: peter-evans/create-or-update-comment@v2 + if: success() && github.event.number && steps.fc.outputs.comment-id == 0 + with: + issue-number: ${{ github.event.number }} + body: ${{ steps.get-comment-body.outputs.body }} + + - name: Update Comment + uses: peter-evans/create-or-update-comment@v2 + if: success() && github.event.number && steps.fc.outputs.comment-id != 0 + with: + issue-number: ${{ github.event.number }} + body: ${{ steps.get-comment-body.outputs.body }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace diff --git a/package.json b/package.json index 329f71c72e..8cc875803d 100644 --- a/package.json +++ b/package.json @@ -135,5 +135,11 @@ "typescript": "4.9.4", "typescript-plugin-css-modules": "^4.2.2", "webpack": "^5.88.2" + }, + "nextBundleAnalysis": { + "budget": null, + "budgetPercentIncreaseRed": 20, + "minimumChangeThreshold": 0, + "showDetails": true } } From 0533d5071de137f0ece6f773d7e0b481c75e0a3c Mon Sep 17 00:00:00 2001 From: Franco Venica Date: Tue, 14 Nov 2023 11:34:35 -0300 Subject: [PATCH 09/11] Add loader to bulk execution + removal submitBtn --- .../flows/ExecuteBatch/ReviewBatch.tsx | 12 ++++++-- .../tx/SignOrExecuteForm/SubmitButton.tsx | 29 ------------------- 2 files changed, 9 insertions(+), 32 deletions(-) delete mode 100644 src/components/tx/SignOrExecuteForm/SubmitButton.tsx diff --git a/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx b/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx index c1277142af..c95deb0b12 100644 --- a/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx +++ b/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx @@ -1,4 +1,4 @@ -import { Typography, Button, CardActions, Divider, Alert } from '@mui/material' +import { CircularProgress, Typography, Button, CardActions, Divider, Alert } from '@mui/material' import useAsync from '@/hooks/useAsync' import { FEATURES } from '@safe-global/safe-gateway-typescript-sdk' import type { TransactionDetails } from '@safe-global/safe-gateway-typescript-sdk' @@ -194,8 +194,14 @@ export const ReviewBatch = ({ params }: { params: ExecuteBatchFlowProps }) => { {(isOk) => ( - )} diff --git a/src/components/tx/SignOrExecuteForm/SubmitButton.tsx b/src/components/tx/SignOrExecuteForm/SubmitButton.tsx deleted file mode 100644 index 8412086eab..0000000000 --- a/src/components/tx/SignOrExecuteForm/SubmitButton.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import CheckWallet from '@/components/common/CheckWallet' -import { Button } from '@mui/material' -import { useContext } from 'react' -import { TxSecurityContext } from '../security/shared/TxSecurityContext' - -const SubmitButton = ({ - willExecute, - submitDisabled, - isEstimating, -}: { - willExecute: boolean - submitDisabled: boolean - isEstimating: boolean -}) => { - const { needsRiskConfirmation, isRiskConfirmed } = useContext(TxSecurityContext) - - const disableButton = submitDisabled || (needsRiskConfirmation && !isRiskConfirmed) - return ( - - {(isOk) => ( - - )} - - ) -} - -export default SubmitButton From 675e49fdfab8920a3075db6184ae8add54a28cd9 Mon Sep 17 00:00:00 2001 From: Franco Venica Date: Sun, 19 Nov 2023 23:03:47 -0300 Subject: [PATCH 10/11] commit with a signature --- src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx b/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx index c95deb0b12..5aeca1b521 100644 --- a/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx +++ b/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx @@ -201,7 +201,7 @@ export const ReviewBatch = ({ params }: { params: ExecuteBatchFlowProps }) => { onClick={handleSubmit} sx={{ minWidth: '114px' }} > - {!isSubmittable ? : 'Submit'} + {!isSubmittable ? : 'Submitt'} )} From e205b600a82275f19c67228a3bd3e59e31d16371 Mon Sep 17 00:00:00 2001 From: Franco Venica Date: Sun, 19 Nov 2023 23:04:26 -0300 Subject: [PATCH 11/11] Reverting the previous dummy change --- src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx b/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx index 5aeca1b521..c95deb0b12 100644 --- a/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx +++ b/src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx @@ -201,7 +201,7 @@ export const ReviewBatch = ({ params }: { params: ExecuteBatchFlowProps }) => { onClick={handleSubmit} sx={{ minWidth: '114px' }} > - {!isSubmittable ? : 'Submitt'} + {!isSubmittable ? : 'Submit'} )}