-
Notifications
You must be signed in to change notification settings - Fork 470
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add: data management tab with import all data button (#1103)
* add: data management tab with import all data button * add: /import route which contains a global data import page * ignore rinkeby for addressbook migration Co-authored-by: Aaron Cook <[email protected]> Co-authored-by: Usame Algan <[email protected]>
- Loading branch information
1 parent
bd3a2e1
commit a26e5a7
Showing
17 changed files
with
623 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import InfoIcon from '@/public/images/notifications/info.svg' | ||
|
||
import Track from '@/components/common/Track' | ||
import { SETTINGS_EVENTS } from '@/services/analytics' | ||
import { Paper, Grid, Typography, Tooltip, SvgIcon, Button } from '@mui/material' | ||
import { useState } from 'react' | ||
import ImportAllDialog from '../ImportAllDialog' | ||
|
||
const DataManagement = () => { | ||
const [modalOpen, setModalOpen] = useState(false) | ||
|
||
return ( | ||
<Paper sx={{ p: 4, mb: 2 }}> | ||
<Grid container spacing={3}> | ||
<Grid item sm={4} xs={12}> | ||
<Typography variant="h4" fontWeight={700}> | ||
Data import | ||
<Tooltip | ||
placement="top" | ||
title="The imported data will overwrite all added Safes and all address book entries" | ||
> | ||
<span> | ||
<SvgIcon | ||
component={InfoIcon} | ||
inheritViewBox | ||
fontSize="small" | ||
color="border" | ||
sx={{ verticalAlign: 'middle', ml: 0.5 }} | ||
/> | ||
</span> | ||
</Tooltip> | ||
</Typography> | ||
</Grid> | ||
<Grid item xs justifyContent="flex-end" display="flex"> | ||
<Track {...SETTINGS_EVENTS.DATA.IMPORT_ALL_BUTTON}> | ||
<Button size="small" variant="contained" onClick={() => setModalOpen(true)}> | ||
Import all data | ||
</Button> | ||
</Track> | ||
|
||
{modalOpen && <ImportAllDialog handleClose={() => setModalOpen(false)} />} | ||
</Grid> | ||
</Grid> | ||
</Paper> | ||
) | ||
} | ||
|
||
export default DataManagement |
138 changes: 138 additions & 0 deletions
138
src/components/settings/ImportAllDialog/__tests__/useGlobalImportFileParser.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { renderHook } from '@/tests/test-utils' | ||
import { ImportErrors, useGlobalImportJsonParser } from '../useGlobalImportFileParser' | ||
|
||
describe('useGlobalImportFileParser', () => { | ||
it('should return undefined values for undefined json', () => { | ||
const { result } = renderHook(() => useGlobalImportJsonParser(undefined)) | ||
expect(result.current).toEqual({ | ||
addedSafes: undefined, | ||
addressBook: undefined, | ||
addressBookEntriesCount: 0, | ||
addedSafesCount: 0, | ||
}) | ||
}) | ||
|
||
it('should return undefined values and error for empty json', () => { | ||
const { result } = renderHook(() => useGlobalImportJsonParser('{ "version": "1.0", "data": "{}" }')) | ||
expect(result.current).toEqual({ | ||
addedSafes: undefined, | ||
addressBook: undefined, | ||
addressBookEntriesCount: 0, | ||
addedSafesCount: 0, | ||
error: ImportErrors.NO_IMPORT_DATA_FOUND, | ||
}) | ||
}) | ||
|
||
it('should return empty objects for invalid json', () => { | ||
const { result } = renderHook(() => useGlobalImportJsonParser('{ invalid: json, ')) | ||
expect(result.current).toEqual({ | ||
addedSafes: undefined, | ||
addressBook: undefined, | ||
addressBookEntriesCount: 0, | ||
addedSafesCount: 0, | ||
error: ImportErrors.INVALID_JSON_FORMAT, | ||
}) | ||
}) | ||
|
||
it('should return empty objects for wrong versions', () => { | ||
const goerliSafeAddress = '0xAecDFD3A19f777F0c03e6bf99AAfB59937d6467b' | ||
const mainnetSafeAddress = '0x7cB6E6Cbc845e79d9CA05F6577141DA36ad398f5' | ||
|
||
const owner1 = '0x3819b800c67Be64029C1393c8b2e0d0d627dADE2' | ||
const owner2 = '0x954cD69f0E902439f99156e3eeDA080752c08401' | ||
|
||
const jsonData = JSON.stringify({ | ||
version: '2.0', | ||
data: { | ||
'_immortal|v2_5__SAFES': `{"${goerliSafeAddress}":{"address":"${goerliSafeAddress}","chainId":"5","threshold":2,"ethBalance":"0.3","totalFiatBalance":"435.08","owners":["${owner1}","${owner2}"],"modules":[],"spendingLimits":[],"balances":[{"tokenAddress":"0x0000000000000000000000000000000000000000","fiatBalance":"435.08100","tokenBalance":"0.3"},{"tokenAddress":"0x61fD3b6d656F39395e32f46E2050953376c3f5Ff","fiatBalance":"0.00000","tokenBalance":"22405.086233211233211233"}],"implementation":{"value":"0x3E5c63644E683549055b9Be8653de26E0B4CD36E"},"loaded":true,"nonce":1,"currentVersion":"1.3.0+L2","needsUpdate":false,"featuresEnabled":["CONTRACT_INTERACTION","DOMAIN_LOOKUP","EIP1559","ERC721","SAFE_APPS","SAFE_TX_GAS_OPTIONAL","SPENDING_LIMIT","TX_SIMULATION","WARNING_BANNER"],"loadedViaUrl":false,"guard":"","collectiblesTag":"1667921524","txQueuedTag":"1667921524","txHistoryTag":"1667400927"}}`, | ||
'_immortal|v2_MAINNET__SAFES': `{"${mainnetSafeAddress}":{"address":"${mainnetSafeAddress}","chainId":"1","threshold":1,"ethBalance":"0","totalFiatBalance":"0.00","owners":["${owner1}","${owner2}"],"modules":[],"spendingLimits":[],"balances":[{"tokenAddress":"0x0000000000000000000000000000000000000000","fiatBalance":"0.00000","tokenBalance":"0"}],"implementation":{"value":"0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552","name":"Gnosis Safe: Singleton 1.3.0","logoUri":"https://safe-transaction-assets.safe.global/contracts/logos/0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552.png"},"loaded":true,"nonce":2,"currentVersion":"1.3.0","needsUpdate":false,"featuresEnabled":["CONTRACT_INTERACTION","DOMAIN_LOOKUP","EIP1559","ERC721","SAFE_APPS","SAFE_TX_GAS_OPTIONAL","SPENDING_LIMIT","TX_SIMULATION"],"loadedViaUrl":false,"guard":"","collectiblesTag":"1667397095","txQueuedTag":"1667397095","txHistoryTag":"1664287235"}}`, | ||
}, | ||
}) | ||
|
||
const { result } = renderHook(() => useGlobalImportJsonParser(jsonData)) | ||
|
||
expect(result.current).toEqual({ | ||
addedSafes: undefined, | ||
addressBook: undefined, | ||
addressBookEntriesCount: 0, | ||
addedSafesCount: 0, | ||
error: ImportErrors.INVALID_VERSION, | ||
}) | ||
}) | ||
|
||
it('should parse added safes correctly', () => { | ||
const goerliSafeAddress = '0xAecDFD3A19f777F0c03e6bf99AAfB59937d6467b' | ||
const mainnetSafeAddress = '0x7cB6E6Cbc845e79d9CA05F6577141DA36ad398f5' | ||
|
||
const owner1 = '0x3819b800c67Be64029C1393c8b2e0d0d627dADE2' | ||
const owner2 = '0x954cD69f0E902439f99156e3eeDA080752c08401' | ||
|
||
const jsonData = JSON.stringify({ | ||
version: '1.0', | ||
data: { | ||
'_immortal|v2_5__SAFES': `{"${goerliSafeAddress}":{"address":"${goerliSafeAddress}","chainId":"5","threshold":2,"ethBalance":"0.3","totalFiatBalance":"435.08","owners":["${owner1}","${owner2}"],"modules":[],"spendingLimits":[],"balances":[{"tokenAddress":"0x0000000000000000000000000000000000000000","fiatBalance":"435.08100","tokenBalance":"0.3"},{"tokenAddress":"0x61fD3b6d656F39395e32f46E2050953376c3f5Ff","fiatBalance":"0.00000","tokenBalance":"22405.086233211233211233"}],"implementation":{"value":"0x3E5c63644E683549055b9Be8653de26E0B4CD36E"},"loaded":true,"nonce":1,"currentVersion":"1.3.0+L2","needsUpdate":false,"featuresEnabled":["CONTRACT_INTERACTION","DOMAIN_LOOKUP","EIP1559","ERC721","SAFE_APPS","SAFE_TX_GAS_OPTIONAL","SPENDING_LIMIT","TX_SIMULATION","WARNING_BANNER"],"loadedViaUrl":false,"guard":"","collectiblesTag":"1667921524","txQueuedTag":"1667921524","txHistoryTag":"1667400927"}}`, | ||
'_immortal|v2_MAINNET__SAFES': `{"${mainnetSafeAddress}":{"address":"${mainnetSafeAddress}","chainId":"1","threshold":1,"ethBalance":"0","totalFiatBalance":"0.00","owners":["${owner1}","${owner2}"],"modules":[],"spendingLimits":[],"balances":[{"tokenAddress":"0x0000000000000000000000000000000000000000","fiatBalance":"0.00000","tokenBalance":"0"}],"implementation":{"value":"0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552","name":"Gnosis Safe: Singleton 1.3.0","logoUri":"https://safe-transaction-assets.safe.global/contracts/logos/0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552.png"},"loaded":true,"nonce":2,"currentVersion":"1.3.0","needsUpdate":false,"featuresEnabled":["CONTRACT_INTERACTION","DOMAIN_LOOKUP","EIP1559","ERC721","SAFE_APPS","SAFE_TX_GAS_OPTIONAL","SPENDING_LIMIT","TX_SIMULATION"],"loadedViaUrl":false,"guard":"","collectiblesTag":"1667397095","txQueuedTag":"1667397095","txHistoryTag":"1664287235"}}`, | ||
}, | ||
}) | ||
const { result } = renderHook(() => useGlobalImportJsonParser(jsonData)) | ||
|
||
const { addedSafes, addedSafesCount, addressBook, addressBookEntriesCount } = result.current | ||
|
||
// No addressbook data | ||
expect(addressBookEntriesCount).toEqual(0) | ||
expect(addressBook).toEqual(undefined) | ||
|
||
expect(addedSafesCount).toEqual(2) | ||
expect(addedSafes).toBeDefined() | ||
if (!addedSafes) { | ||
fail('No added safes found') | ||
} | ||
expect(addedSafes['5'][goerliSafeAddress]).toBeDefined() | ||
const goerliAddedSafe = addedSafes['5'][goerliSafeAddress] | ||
expect(goerliAddedSafe.threshold).toEqual(2) | ||
|
||
expect(addedSafes['1'][mainnetSafeAddress]).toBeDefined() | ||
const mainnetAddedSafe = addedSafes['1'][mainnetSafeAddress] | ||
expect(mainnetAddedSafe.threshold).toEqual(1) | ||
}) | ||
|
||
it('should parse address book entries correctly', () => { | ||
const goerliAddress1 = '0xAecDFD3A19f777F0c03e6bf99AAfB59937d6467b' | ||
const goerliName1 = 'test.eth' | ||
const goerliAddress2 = '0x3819b800c67Be64029C1393c8b2e0d0d627dADE2' | ||
const goerliName2 = 'some.eth' | ||
const mainnetAddress1 = '0x954cD69f0E902439f99156e3eeDA080752c08401' | ||
const mainnetName1 = 'mobile owner' | ||
const mainnetAddress2 = '0x7cB6E6Cbc845e79d9CA05F6577141DA36ad398f5' | ||
const mainnetName2 = 'S0mE&W3!rd#N4m€' | ||
|
||
const jsonData = JSON.stringify({ | ||
version: '1.0', | ||
data: { | ||
SAFE__addressBook: `[{"address":"${mainnetAddress1}","name":"${mainnetName1}","chainId":"1"}, | ||
{"address":"${mainnetAddress2}","name":"${mainnetName2}","chainId":"1"}, | ||
{"address":"${goerliAddress1}","name":"${goerliName1}","chainId":"5"}, | ||
{"address":"${goerliAddress2}","name":"${goerliName2}","chainId":"5"}]`, | ||
}, | ||
}) | ||
|
||
const { result } = renderHook(() => useGlobalImportJsonParser(jsonData)) | ||
|
||
const { addedSafes, addedSafesCount, addressBook, addressBookEntriesCount } = result.current | ||
|
||
// no added safes | ||
// No addressbook data | ||
expect(addedSafesCount).toEqual(0) | ||
expect(addedSafes).toEqual(undefined) | ||
|
||
expect(addressBookEntriesCount).toEqual(4) | ||
if (!addressBook) { | ||
fail('No addressbook migrated') | ||
} | ||
expect(addressBook['5'][goerliAddress1]).toEqual(goerliName1) | ||
expect(addressBook['5'][goerliAddress2]).toEqual(goerliName2) | ||
|
||
expect(addressBook['1'][mainnetAddress1]).toEqual(mainnetName1) | ||
expect(addressBook['1'][mainnetAddress2]).toEqual(mainnetName2) | ||
}) | ||
}) |
Oops, something went wrong.