Skip to content

Commit

Permalink
Feat: include recently visited safes in import and export data [SW-59…
Browse files Browse the repository at this point in the history
…4] (#4630)

* feat: include last visited safes in import/export data

* fix: prevent unecessary requests when wallet is undefined and retry with backoff when gateway returns 503

* use empty object as default for AllOwnedSafes type

* Add visited safes to import and export previews
  • Loading branch information
jmealy authored Dec 13, 2024
1 parent 6939359 commit 52d6300
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 5 deletions.
17 changes: 17 additions & 0 deletions src/components/settings/DataManagement/FileListCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { UndeployedSafesState } from '@/features/counterfactual/store/undep
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'

import css from './styles.module.css'
import type { VisitedSafesState } from '@/store/visitedSafesSlice'

const getItemSecondaryText = (
chains: ChainInfo[],
Expand Down Expand Up @@ -53,6 +54,7 @@ type Data = {
settings?: SettingsState
safeApps?: SafeAppsState
undeployedSafes?: UndeployedSafesState
visitedSafes?: VisitedSafesState
error?: string
}

Expand All @@ -68,6 +70,7 @@ const getItems = ({
settings,
safeApps,
undeployedSafes,
visitedSafes,
error,
chains,
showPreview = false,
Expand Down Expand Up @@ -120,6 +123,18 @@ const getItems = ({
items.push(settingsPreview)
}

if (visitedSafes) {
const visitedSafesPreview: ListItemTextProps = {
primary: (
<>
<b>Visited Safe Accounts history</b>
</>
),
}

items.push(visitedSafesPreview)
}

const hasBookmarkedSafeApps = Object.values(safeApps || {}).some((chainId) => chainId.pinned?.length > 0)
if (hasBookmarkedSafeApps) {
const safeAppsPreview: ListItemTextProps = {
Expand Down Expand Up @@ -160,6 +175,7 @@ export const FileListCard = ({
settings,
safeApps,
undeployedSafes,
visitedSafes,
error,
showPreview = false,
...cardHeaderProps
Expand All @@ -170,6 +186,7 @@ export const FileListCard = ({
addressBook,
settings,
safeApps,
visitedSafes,
undeployedSafes,
error,
chains: chains.configs,
Expand Down
12 changes: 10 additions & 2 deletions src/components/settings/DataManagement/ImportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useGlobalImportJsonParser } from '@/components/settings/DataManagement/
import FileIcon from '@/public/images/settings/data/file.svg'
import { ImportFileUpload } from '@/components/settings/DataManagement/ImportFileUpload'
import { showNotification } from '@/store/notificationsSlice'
import { visitedSafesSlice } from '@/store/visitedSafesSlice'

import css from './styles.module.css'

Expand All @@ -31,10 +32,11 @@ export const ImportDialog = ({
setJsonData: Dispatch<SetStateAction<string | undefined>>
}): ReactElement => {
const dispatch = useAppDispatch()
const { addedSafes, addressBook, addressBookEntriesCount, settings, safeApps, undeployedSafes, error } =
const { addedSafes, addressBook, addressBookEntriesCount, settings, safeApps, undeployedSafes, visitedSafes, error } =
useGlobalImportJsonParser(jsonData)

const isDisabled = (!addedSafes && !addressBook && !settings && !safeApps) || !!error
const isDisabled =
(!addedSafes && !addressBook && !settings && !safeApps && !undeployedSafes && !visitedSafes) || !!error

const handleClose = () => {
setFileName(undefined)
Expand Down Expand Up @@ -73,6 +75,11 @@ export const ImportDialog = ({
trackEvent(SETTINGS_EVENTS.DATA.IMPORT_UNDEPLOYED_SAFES)
}

if (visitedSafes) {
dispatch(visitedSafesSlice.actions.setVisitedSafes(visitedSafes))
trackEvent(SETTINGS_EVENTS.DATA.IMPORT_VISITED_SAFES)
}

dispatch(
showNotification({
variant: 'success',
Expand Down Expand Up @@ -110,6 +117,7 @@ export const ImportDialog = ({
addressBook={addressBook}
settings={settings}
safeApps={safeApps}
visitedSafes={visitedSafes}
undeployedSafes={undeployedSafes}
error={error}
showPreview
Expand Down
7 changes: 6 additions & 1 deletion src/components/settings/DataManagement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ImportFileUpload } from '@/components/settings/DataManagement/ImportFil
import { ImportDialog } from '@/components/settings/DataManagement/ImportDialog'
import { SAFE_EXPORT_VERSION } from '@/components/settings/DataManagement/useGlobalImportFileParser'
import { FileListCard } from '@/components/settings/DataManagement/FileListCard'
import { selectAllVisitedSafes, visitedSafesSlice } from '@/store/visitedSafesSlice'

import css from './styles.module.css'
import Track from '@/components/common/Track'
Expand All @@ -31,6 +32,7 @@ export const exportAppData = () => {
[settingsSlice.name]: setting,
[safeAppsSlice.name]: safeApps,
[undeployedSafesSlice.name]: undeployedSafes,
[visitedSafesSlice.name]: visitedSafes,
} = getPersistedState()

// Ensure they are under the same name as the slice
Expand All @@ -40,9 +42,10 @@ export const exportAppData = () => {
[settingsSlice.name]: setting,
[safeAppsSlice.name]: safeApps,
[undeployedSafesSlice.name]: undeployedSafes,
[visitedSafesSlice.name]: visitedSafes,
}

const data = JSON.stringify({ version: SAFE_EXPORT_VERSION.V2, data: exportData })
const data = JSON.stringify({ version: SAFE_EXPORT_VERSION.V3, data: exportData })

const blob = new Blob([data], { type: 'text/json' })
const link = document.createElement('a')
Expand All @@ -61,6 +64,7 @@ const DataManagement = () => {
const addedSafes = useAppSelector(selectAllAddedSafes)
const addressBook = useAppSelector(selectAllAddressBooks)
const settings = useAppSelector(selectSettings)
const visitedSafes = useAppSelector(selectAllVisitedSafes)
const safeApps = useAppSelector(selectSafeApps)
const undeployedSafes = useAppSelector(selectUndeployedSafes)

Expand Down Expand Up @@ -99,6 +103,7 @@ const DataManagement = () => {
addedSafes={addedSafes}
addressBook={addressBook}
settings={settings}
visitedSafes={visitedSafes}
safeApps={safeApps}
undeployedSafes={undeployedSafes}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import type { SettingsState } from '@/store/settingsSlice'
import type { UndeployedSafesState } from '@/features/counterfactual/store/undeployedSafesSlice'

import { useMemo } from 'react'
import type { VisitedSafesState } from '@/store/visitedSafesSlice'

export const enum SAFE_EXPORT_VERSION {
V1 = '1.0',
V2 = '2.0',
V3 = '3.0',
}

export enum ImportErrors {
Expand Down Expand Up @@ -59,6 +61,13 @@ export const _filterValidAbEntries = (ab?: AddressBookState): AddressBookState |
* - safeApps
* - settings
*
* 3.0:
* - address book
* - added Safes
* - safeApps
* - settings
* - visited Safes
*
* @param jsonData
* @returns data to import and some insights about it
*/
Expand All @@ -69,6 +78,7 @@ type Data = {
settings?: SettingsState
safeApps?: SafeAppsState
undeployedSafes?: UndeployedSafesState
visitedSafes?: VisitedSafesState
error?: ImportErrors
addressBookEntriesCount: number
addedSafesCount: number
Expand All @@ -84,6 +94,7 @@ export const useGlobalImportJsonParser = (jsonData: string | undefined): Data =>
settings: undefined,
safeApps: undefined,
undeployedSafes: undefined,
visitedSafes: undefined,
}

if (!jsonData) {
Expand Down Expand Up @@ -124,6 +135,17 @@ export const useGlobalImportJsonParser = (jsonData: string | undefined): Data =>
break
}

case SAFE_EXPORT_VERSION.V3: {
data.addressBook = _filterValidAbEntries(parsedFile.data.addressBook)
data.addedSafes = parsedFile.data.addedSafes
data.settings = parsedFile.data.settings
data.safeApps = parsedFile.data.safeApps
data.undeployedSafes = parsedFile.data.undeployedSafes
data.visitedSafes = parsedFile.data.visitedSafes

break
}

default: {
data.error = ImportErrors.INVALID_VERSION
}
Expand Down
2 changes: 1 addition & 1 deletion src/features/myAccounts/hooks/useAllOwnedSafes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const useAllOwnedSafes = (address: string): AsyncResult<AllOwnedSafes> => {
}
}, [data, setCache])

return [cache, asError(error), isLoading]
return address ? [cache, asError(error), isLoading] : [{}, undefined, false]
}

export default useAllOwnedSafes
4 changes: 4 additions & 0 deletions src/services/analytics/events/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ export const SETTINGS_EVENTS = {
action: 'Imported counterfactual safes via Import all',
category: SETTINGS_CATEGORY,
},
IMPORT_VISITED_SAFES: {
action: 'Imported visited safes via Import all',
category: SETTINGS_CATEGORY,
},
},
ENV_VARIABLES: {
SAVE: {
Expand Down
1 change: 0 additions & 1 deletion src/store/api/gateway/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { proposerEndpoints } from '@/store/api/gateway/proposers'
import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'

import {
type AllOwnedSafes,
getAllOwnedSafes,
Expand Down
4 changes: 4 additions & 0 deletions src/store/visitedSafesSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export const visitedSafesSlice = createSlice({
state[chainId] ??= {}
state[chainId][address] = { lastVisited }
},
setVisitedSafes: (_, { payload }: PayloadAction<VisitedSafesState>) => {
// We must return as we are overwriting the entire state
return payload
},
},
})

Expand Down

0 comments on commit 52d6300

Please sign in to comment.