Merge pull request #1411 from gnosis/release/v2.12.0

Backmerge 2.12.0 to development
This commit is contained in:
Daniel Sanchez 2020-09-29 17:18:23 +02:00 committed by GitHub
commit 24f2828a7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 101 additions and 65 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "safe-react", "name": "safe-react",
"version": "2.11.1", "version": "2.12.0",
"description": "Allowing crypto users manage funds in a safer way", "description": "Allowing crypto users manage funds in a safer way",
"website": "https://github.com/gnosis/safe-react#readme", "website": "https://github.com/gnosis/safe-react#readme",
"bugs": { "bugs": {

View File

@ -1,17 +1,9 @@
import updateSafe from './updateSafe' import { Set } from 'immutable'
import updateAssetsList from './updateAssetsList'
import { Dispatch } from 'src/logic/safe/store/actions/types.d'
// the selector uses ownProps argument/router props to get the address of the safe const updateActiveAssets = (safeAddress: string, activeAssets: Set<string>) => (dispatch: Dispatch): void => {
// so in order to use it I had to recreate the same structure dispatch(updateAssetsList({ safeAddress, activeAssets }))
// const generateMatchProps = (safeAddress: string) => ({
// match: {
// params: {
// [SAFE_PARAM_ADDRESS]: safeAddress,
// },
// },
// })
const updateActiveAssets = (safeAddress, activeAssets) => async (dispatch) => {
dispatch(updateSafe({ address: safeAddress, activeAssets }))
} }
export default updateActiveAssets export default updateActiveAssets

View File

@ -1,6 +1,6 @@
import updateSafe from './updateSafe'
import { Set } from 'immutable' import { Set } from 'immutable'
import { Dispatch } from 'redux' import updateTokensList from './updateTokensList'
import { Dispatch } from 'src/logic/safe/store/actions/types.d'
// the selector uses ownProps argument/router props to get the address of the safe // the selector uses ownProps argument/router props to get the address of the safe
// so in order to use it I had to recreate the same structure // so in order to use it I had to recreate the same structure
@ -13,7 +13,7 @@ import { Dispatch } from 'redux'
// }) // })
const updateActiveTokens = (safeAddress: string, activeTokens: Set<string>) => (dispatch: Dispatch): void => { const updateActiveTokens = (safeAddress: string, activeTokens: Set<string>) => (dispatch: Dispatch): void => {
dispatch(updateSafe({ address: safeAddress, activeTokens })) dispatch(updateTokensList({ safeAddress, activeTokens }))
} }
export default updateActiveTokens export default updateActiveTokens

View File

@ -0,0 +1,7 @@
import { createAction } from 'redux-actions'
export const UPDATE_ASSETS_LIST = 'UPDATE_ASSETS_LIST'
const updateAssetsList = createAction(UPDATE_ASSETS_LIST)
export default updateAssetsList

View File

@ -1,7 +1,9 @@
import updateSafe from './updateSafe' import { Set } from 'immutable'
import updateAssetsList from './updateAssetsList'
import { Dispatch } from 'src/logic/safe/store/actions/types.d'
const updateBlacklistedAssets = (safeAddress, blacklistedAssets) => async (dispatch) => { const updateBlacklistedAssets = (safeAddress: string, blacklistedAssets: Set<string>) => (dispatch: Dispatch): void => {
dispatch(updateSafe({ address: safeAddress, blacklistedAssets })) dispatch(updateAssetsList({ safeAddress, blacklistedAssets }))
} }
export default updateBlacklistedAssets export default updateBlacklistedAssets

View File

@ -1,9 +1,9 @@
import updateSafe from './updateSafe'
import { Dispatch } from 'redux'
import { Set } from 'immutable' import { Set } from 'immutable'
import updateTokensList from './updateTokensList'
import { Dispatch } from 'src/logic/safe/store/actions/types.d'
const updateBlacklistedTokens = (safeAddress: string, blacklistedTokens: Set<string>) => (dispatch: Dispatch): void => { const updateBlacklistedTokens = (safeAddress: string, blacklistedTokens: Set<string>) => (dispatch: Dispatch): void => {
dispatch(updateSafe({ address: safeAddress, blacklistedTokens })) dispatch(updateTokensList({ safeAddress, blacklistedTokens }))
} }
export default updateBlacklistedTokens export default updateBlacklistedTokens

View File

@ -0,0 +1,7 @@
import { createAction } from 'redux-actions'
export const UPDATE_TOKENS_LIST = 'UPDATE_TOKENS_LIST'
const updateTokenList = createAction(UPDATE_TOKENS_LIST)
export default updateTokenList

View File

@ -11,6 +11,8 @@ import { REMOVE_SAFE_OWNER } from 'src/logic/safe/store/actions/removeSafeOwner'
import { REPLACE_SAFE_OWNER } from 'src/logic/safe/store/actions/replaceSafeOwner' import { REPLACE_SAFE_OWNER } from 'src/logic/safe/store/actions/replaceSafeOwner'
import { SET_DEFAULT_SAFE } from 'src/logic/safe/store/actions/setDefaultSafe' import { SET_DEFAULT_SAFE } from 'src/logic/safe/store/actions/setDefaultSafe'
import { UPDATE_SAFE } from 'src/logic/safe/store/actions/updateSafe' import { UPDATE_SAFE } from 'src/logic/safe/store/actions/updateSafe'
import { UPDATE_TOKENS_LIST } from 'src/logic/safe/store/actions/updateTokensList'
import { UPDATE_ASSETS_LIST } from 'src/logic/safe/store/actions/updateAssetsList'
import { getActiveTokensAddressesForAllSafes, safesMapSelector } from 'src/logic/safe/store/selectors' import { getActiveTokensAddressesForAllSafes, safesMapSelector } from 'src/logic/safe/store/selectors'
import { checksumAddress } from 'src/utils/checksumAddress' import { checksumAddress } from 'src/utils/checksumAddress'
import { makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook' import { makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook'
@ -31,6 +33,8 @@ const watchedActions = [
REPLACE_SAFE_OWNER, REPLACE_SAFE_OWNER,
EDIT_SAFE_OWNER, EDIT_SAFE_OWNER,
ACTIVATE_TOKEN_FOR_ALL_SAFES, ACTIVATE_TOKEN_FOR_ALL_SAFES,
UPDATE_TOKENS_LIST,
UPDATE_ASSETS_LIST,
SET_DEFAULT_SAFE, SET_DEFAULT_SAFE,
] ]

View File

@ -11,11 +11,14 @@ import { REPLACE_SAFE_OWNER } from 'src/logic/safe/store/actions/replaceSafeOwne
import { SET_DEFAULT_SAFE } from 'src/logic/safe/store/actions/setDefaultSafe' import { SET_DEFAULT_SAFE } from 'src/logic/safe/store/actions/setDefaultSafe'
import { SET_LATEST_MASTER_CONTRACT_VERSION } from 'src/logic/safe/store/actions/setLatestMasterContractVersion' import { SET_LATEST_MASTER_CONTRACT_VERSION } from 'src/logic/safe/store/actions/setLatestMasterContractVersion'
import { UPDATE_SAFE } from 'src/logic/safe/store/actions/updateSafe' import { UPDATE_SAFE } from 'src/logic/safe/store/actions/updateSafe'
import { UPDATE_TOKENS_LIST } from 'src/logic/safe/store/actions/updateTokensList'
import { UPDATE_ASSETS_LIST } from 'src/logic/safe/store/actions/updateAssetsList'
import { makeOwner } from 'src/logic/safe/store/models/owner' import { makeOwner } from 'src/logic/safe/store/models/owner'
import makeSafe, { SafeRecordProps } from 'src/logic/safe/store/models/safe' import makeSafe, { SafeRecordProps } from 'src/logic/safe/store/models/safe'
import { checksumAddress } from 'src/utils/checksumAddress' import { checksumAddress } from 'src/utils/checksumAddress'
import { SafeReducerMap } from 'src/routes/safe/store/reducer/types/safe' import { SafeReducerMap } from 'src/routes/safe/store/reducer/types/safe'
import { ADD_OR_UPDATE_SAFE } from 'src/logic/safe/store/actions/addOrUpdateSafe' import { ADD_OR_UPDATE_SAFE } from 'src/logic/safe/store/actions/addOrUpdateSafe'
import { sameAddress } from 'src/logic/wallets/ethAddresses'
export const SAFE_REDUCER_ID = 'safes' export const SAFE_REDUCER_ID = 'safes'
export const DEFAULT_SAFE_INITIAL_STATE = 'NOT_ASKED' export const DEFAULT_SAFE_INITIAL_STATE = 'NOT_ASKED'
@ -51,10 +54,10 @@ const updateSafeProps = (prevSafe, safe) => {
// We check each safe property sent in action.payload // We check each safe property sent in action.payload
safeProperties.forEach((key) => { safeProperties.forEach((key) => {
if (safe[key] && typeof safe[key] === 'object') { if (safe[key] && typeof safe[key] === 'object') {
if (safe[key].length) { if (safe[key].length >= 0) {
// If type is array we update the array // If type is array we update the array
record.update(key, () => safe[key]) record.update(key, () => safe[key])
} else if (safe[key].size) { } else if (safe[key].size >= 0) {
// If type is Immutable List we replace current List // If type is Immutable List we replace current List
// If type is Object we do a merge // If type is Object we do a merge
List.isList(safe[key]) List.isList(safe[key])
@ -130,6 +133,14 @@ export default handleActions(
[ADD_SAFE_OWNER]: (state: SafeReducerMap, action) => { [ADD_SAFE_OWNER]: (state: SafeReducerMap, action) => {
const { ownerAddress, ownerName, safeAddress } = action.payload const { ownerAddress, ownerName, safeAddress } = action.payload
const addressFound = state
.getIn(['safes', safeAddress])
.owners.find((owner) => sameAddress(owner.address, ownerAddress))
if (addressFound) {
return state
}
return state.updateIn(['safes', safeAddress], (prevSafe) => return state.updateIn(['safes', safeAddress], (prevSafe) =>
prevSafe.merge({ prevSafe.merge({
owners: prevSafe.owners.push(makeOwner({ address: ownerAddress, name: ownerName })), owners: prevSafe.owners.push(makeOwner({ address: ownerAddress, name: ownerName })),
@ -167,6 +178,24 @@ export default handleActions(
return prevSafe.merge({ owners: updatedOwners }) return prevSafe.merge({ owners: updatedOwners })
}) })
}, },
[UPDATE_TOKENS_LIST]: (state: SafeReducerMap, action) => {
// Only activeTokens or blackListedTokens is required
const { safeAddress, activeTokens, blacklistedTokens } = action.payload
const key = activeTokens ? 'activeTokens' : 'blacklistedTokens'
const list = activeTokens ?? blacklistedTokens
return state.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.set(key, list))
},
[UPDATE_ASSETS_LIST]: (state: SafeReducerMap, action) => {
// Only activeAssets or blackListedAssets is required
const { safeAddress, activeAssets, blacklistedAssets } = action.payload
const key = activeAssets ? 'activeAssets' : 'blacklistedAssets'
const list = activeAssets ?? blacklistedAssets
return state.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.set(key, list))
},
[SET_DEFAULT_SAFE]: (state: SafeReducerMap, action) => state.set('defaultSafe', action.payload), [SET_DEFAULT_SAFE]: (state: SafeReducerMap, action) => state.set('defaultSafe', action.payload),
[SET_LATEST_MASTER_CONTRACT_VERSION]: (state: SafeReducerMap, action) => [SET_LATEST_MASTER_CONTRACT_VERSION]: (state: SafeReducerMap, action) =>
state.set('latestMasterContractVersion', action.payload), state.set('latestMasterContractVersion', action.payload),

View File

@ -30,15 +30,13 @@ describe('Feature > Balances', () => {
const expectedResult = '100' const expectedResult = '100'
// when // when
store.dispatch(updateActiveTokens(safeAddress, Set([token.address])))
store.dispatch(updateSafe({ address: safeAddress, balances })) store.dispatch(updateSafe({ address: safeAddress, balances }))
store.dispatch(updateActiveTokens(safeAddress, Set([token.address])))
const safe = safesMapSelector(store.getState()).get(safeAddress) const safe = safesMapSelector(store.getState()).get(safeAddress)
//@ts-ignore const balanceResult = safe?.get('balances').get(token.address)
const balanceResult = safe.get('balances').get(token.address) const activeTokens = safe?.get('activeTokens')
//@ts-ignore const tokenIsActive = activeTokens?.has(token.address)
const activeTokens = safe.get('activeTokens')
const tokenIsActive = activeTokens.has(token.address)
// then // then
expect(balanceResult).toBe(expectedResult) expect(balanceResult).toBe(expectedResult)
@ -53,8 +51,7 @@ describe('Feature > Balances', () => {
// when // when
store.dispatch(updateSafe({ address: safeAddress, ethBalance: etherAmount })) store.dispatch(updateSafe({ address: safeAddress, ethBalance: etherAmount }))
const safe = safesMapSelector(store.getState()).get(safeAddress) const safe = safesMapSelector(store.getState()).get(safeAddress)
//@ts-ignore const balanceResult = safe?.get('ethBalance')
const balanceResult = safe.get('ethBalance')
// then // then
expect(balanceResult).toBe(expectedResult) expect(balanceResult).toBe(expectedResult)

View File

@ -4,7 +4,7 @@ import { makeStyles } from '@material-ui/core/styles'
import Search from '@material-ui/icons/Search' import Search from '@material-ui/icons/Search'
import cn from 'classnames' import cn from 'classnames'
import SearchBar from 'material-ui-search-bar' import SearchBar from 'material-ui-search-bar'
import React, { useEffect, useState } from 'react' import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { FixedSizeList } from 'react-window' import { FixedSizeList } from 'react-window'
@ -55,11 +55,6 @@ const AssetsList = (props) => {
const [blacklistedAssetsAddresses, setBlacklistedAssetsAddresses] = useState(blacklistedAssets) const [blacklistedAssetsAddresses, setBlacklistedAssetsAddresses] = useState(blacklistedAssets)
const nftAssetsList = useSelector(nftAssetsListSelector) const nftAssetsList = useSelector(nftAssetsListSelector)
useEffect(() => {
dispatch(updateActiveAssets(safeAddress, activeAssetsAddresses))
dispatch(updateBlacklistedAssets(safeAddress, blacklistedAssetsAddresses))
}, [activeAssetsAddresses, blacklistedAssetsAddresses, dispatch, safeAddress])
const onCancelSearch = () => { const onCancelSearch = () => {
setFilterValue('') setFilterValue('')
} }
@ -73,19 +68,22 @@ const AssetsList = (props) => {
} }
const onSwitch = (asset) => () => { const onSwitch = (asset) => () => {
const { address } = asset let newActiveAssetsAddresses
const activeAssetsAddressesResult = activeAssetsAddresses.contains(address) let newBlacklistedAssetsAddresses
? activeAssetsAddresses.remove(address) if (activeAssetsAddresses.has(asset.address)) {
: activeAssetsAddresses.add(address) newActiveAssetsAddresses = activeAssetsAddresses.delete(asset.address)
const blacklistedAssetsAddressesResult = activeAssetsAddresses.has(address) newBlacklistedAssetsAddresses = blacklistedAssetsAddresses.add(asset.address)
? blacklistedAssetsAddresses.add(address) } else {
: blacklistedAssetsAddresses.remove(address) newActiveAssetsAddresses = activeAssetsAddresses.add(asset.address)
setActiveAssetsAddresses(activeAssetsAddressesResult) newBlacklistedAssetsAddresses = blacklistedAssetsAddresses.delete(asset.address)
setBlacklistedAssetsAddresses(blacklistedAssetsAddressesResult)
return {
activeAssetsAddresses: activeAssetsAddressesResult,
blacklistedAssetsAddresses: blacklistedAssetsAddressesResult,
} }
// Set local state
setActiveAssetsAddresses(newActiveAssetsAddresses)
setBlacklistedAssetsAddresses(newBlacklistedAssetsAddresses)
// Dispatch to global state
dispatch(updateActiveAssets(safeAddress, newActiveAssetsAddresses))
dispatch(updateBlacklistedAssets(safeAddress, newBlacklistedAssetsAddresses))
} }
const createItemData = (assetsList) => { const createItemData = (assetsList) => {

View File

@ -5,7 +5,7 @@ import Search from '@material-ui/icons/Search'
import cn from 'classnames' import cn from 'classnames'
import { List, Set } from 'immutable' import { List, Set } from 'immutable'
import SearchBar from 'material-ui-search-bar' import SearchBar from 'material-ui-search-bar'
import * as React from 'react' import React, { useState } from 'react'
import { FixedSizeList } from 'react-window' import { FixedSizeList } from 'react-window'
import TokenRow from './TokenRow' import TokenRow from './TokenRow'
@ -17,7 +17,6 @@ import Button from 'src/components/layout/Button'
import Divider from 'src/components/layout/Divider' import Divider from 'src/components/layout/Divider'
import Hairline from 'src/components/layout/Hairline' import Hairline from 'src/components/layout/Hairline'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import { useEffect, useState } from 'react'
import { Token } from 'src/logic/tokens/store/model/token' import { Token } from 'src/logic/tokens/store/model/token'
import { useDispatch } from 'react-redux' import { useDispatch } from 'react-redux'
import updateBlacklistedTokens from 'src/logic/safe/store/actions/updateBlacklistedTokens' import updateBlacklistedTokens from 'src/logic/safe/store/actions/updateBlacklistedTokens'
@ -51,13 +50,6 @@ export const TokenList = (props: Props): React.ReactElement => {
const [filter, setFilter] = useState('') const [filter, setFilter] = useState('')
const dispatch = useDispatch() const dispatch = useDispatch()
useEffect(() => {
return () => {
dispatch(updateActiveTokens(safeAddress, activeTokensAddresses))
dispatch(updateBlacklistedTokens(safeAddress, blacklistedTokensAddresses))
}
}, [dispatch, safeAddress, activeTokensAddresses, blacklistedTokensAddresses])
const searchClasses = { const searchClasses = {
input: classes.searchInput, input: classes.searchInput,
root: classes.searchRoot, root: classes.searchRoot,
@ -75,14 +67,22 @@ export const TokenList = (props: Props): React.ReactElement => {
} }
const onSwitch = (token: Token) => () => { const onSwitch = (token: Token) => () => {
let newActiveTokensAddresses
let newBlacklistedTokensAddresses
if (activeTokensAddresses.has(token.address)) { if (activeTokensAddresses.has(token.address)) {
const newTokens = activeTokensAddresses.remove(token.address) newActiveTokensAddresses = activeTokensAddresses.delete(token.address)
setActiveTokensAddresses(newTokens) newBlacklistedTokensAddresses = blacklistedTokensAddresses.add(token.address)
setBlacklistedTokensAddresses(blacklistedTokensAddresses.add(token.address))
} else { } else {
setActiveTokensAddresses(activeTokensAddresses.add(token.address)) newActiveTokensAddresses = activeTokensAddresses.add(token.address)
setBlacklistedTokensAddresses(blacklistedTokensAddresses.remove(token.address)) newBlacklistedTokensAddresses = blacklistedTokensAddresses.delete(token.address)
} }
// Set local state
setActiveTokensAddresses(newActiveTokensAddresses)
setBlacklistedTokensAddresses(newBlacklistedTokensAddresses)
// Dispatch to global state
dispatch(updateActiveTokens(safeAddress, newActiveTokensAddresses))
dispatch(updateBlacklistedTokens(safeAddress, newBlacklistedTokensAddresses))
} }
const createItemData = ( const createItemData = (