Fetch apps from external resource (#2129)
* Configure Safe Apps list with URL parameter * Fix load in AppFrame to allow deleting only manually added apps
This commit is contained in:
parent
69cc936835
commit
072d9d9980
|
@ -0,0 +1,21 @@
|
|||
import axios from 'axios'
|
||||
|
||||
import { SAFE_APPS_LIST_URL } from 'src/utils/constants'
|
||||
|
||||
export type TokenListResult = {
|
||||
name: string
|
||||
timestamp: string
|
||||
apps: AppData[]
|
||||
}
|
||||
|
||||
export type AppData = {
|
||||
url: string
|
||||
name?: string
|
||||
disabled?: boolean
|
||||
description?: string
|
||||
networks: number[]
|
||||
}
|
||||
|
||||
export const fetchSafeAppsList = async (): Promise<TokenListResult> => {
|
||||
return axios.get(SAFE_APPS_LIST_URL).then(({ data }) => data)
|
||||
}
|
|
@ -27,7 +27,7 @@ import { SAFELIST_ADDRESS } from 'src/routes/routes'
|
|||
import { isSameURL } from 'src/utils/url'
|
||||
import { useAnalytics, SAFE_NAVIGATION_EVENT } from 'src/utils/googleAnalytics'
|
||||
import { loadFromStorage, saveToStorage } from 'src/utils/storage'
|
||||
import { staticAppsList } from 'src/routes/safe/components/Apps/utils'
|
||||
import { useAppList } from '../hooks/useAppList'
|
||||
import { LoadingContainer } from 'src/components/LoaderContainer/index'
|
||||
import { TIMEOUT } from 'src/utils/constants'
|
||||
import { web3ReadOnly } from 'src/logic/wallets/getWeb3'
|
||||
|
@ -103,6 +103,7 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
|
|||
const { trackEvent } = useAnalytics()
|
||||
const history = useHistory()
|
||||
const { consentReceived, onConsentReceipt } = useLegalConsent()
|
||||
const { staticAppsList } = useAppList()
|
||||
|
||||
const matchSafeWithAddress = useRouteMatch<{ safeAddress: string }>({ path: `${SAFELIST_ADDRESS}/:safeAddress` })
|
||||
|
||||
|
@ -267,9 +268,10 @@ const AppFrame = ({ appUrl }: Props): React.ReactElement => {
|
|||
setIsAppDeletable(!existsStaticApp)
|
||||
setSafeApp(app)
|
||||
}
|
||||
|
||||
loadApp()
|
||||
}, [appUrl])
|
||||
if (staticAppsList.length) {
|
||||
loadApp()
|
||||
}
|
||||
}, [appUrl, staticAppsList])
|
||||
|
||||
//track GA
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
import { loadFromStorage } from 'src/utils/storage'
|
||||
import { APPS_STORAGE_KEY, getAppInfoFromUrl, getEmptySafeApp, staticAppsList } from '../utils'
|
||||
import { APPS_STORAGE_KEY, getAppInfoFromUrl, getAppsList, getEmptySafeApp } from '../utils'
|
||||
import { AppData } from '../api/fetchSafeAppsList'
|
||||
import { SafeApp, StoredSafeApp, SAFE_APP_FETCH_STATUS } from '../types.d'
|
||||
import { getNetworkId } from 'src/config'
|
||||
|
||||
type UseAppListReturnType = {
|
||||
appList: SafeApp[]
|
||||
staticAppsList: AppData[]
|
||||
}
|
||||
|
||||
const useAppList = (): UseAppListReturnType => {
|
||||
const [appList, setAppList] = useState<SafeApp[]>([])
|
||||
const [staticAppsList, setStaticAppsList] = useState<AppData[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
const loadAppsList = async () => {
|
||||
const remoteAppsList = await getAppsList()
|
||||
setStaticAppsList(remoteAppsList)
|
||||
}
|
||||
|
||||
if (!staticAppsList.length) {
|
||||
loadAppsList()
|
||||
}
|
||||
}, [staticAppsList])
|
||||
|
||||
// Load apps list
|
||||
// for each URL we return a mocked safe-app with a loading status
|
||||
|
@ -42,21 +56,31 @@ const useAppList = (): UseAppListReturnType => {
|
|||
.filter((app) => (!app.networks ? true : app.networks.includes(getNetworkId())))
|
||||
.map((app) => ({
|
||||
...getEmptySafeApp(),
|
||||
...app,
|
||||
url: app.url.trim(),
|
||||
}))
|
||||
|
||||
setAppList(apps)
|
||||
|
||||
apps.forEach((app) => getAppInfoFromUrl(app.url).then(fetchAppCallback))
|
||||
apps.forEach((app) => {
|
||||
if (!app.name || app.name === 'unknown') {
|
||||
// We are using legacy mode, we have to fetch info from manifest
|
||||
getAppInfoFromUrl(app.url).then(fetchAppCallback)
|
||||
} else {
|
||||
// We already have manifest information so we directly add the app
|
||||
fetchAppCallback(app)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!appList.length) {
|
||||
if (staticAppsList.length) {
|
||||
loadApps()
|
||||
}
|
||||
}, [appList])
|
||||
}, [staticAppsList])
|
||||
|
||||
return {
|
||||
appList,
|
||||
staticAppsList,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import { SafeApp, SAFE_APP_FETCH_STATUS } from './types.d'
|
|||
import { getContentFromENS } from 'src/logic/wallets/getWeb3'
|
||||
import appsIconSvg from 'src/assets/icons/apps.svg'
|
||||
import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
|
||||
import { AppData, fetchSafeAppsList } from './api/fetchSafeAppsList'
|
||||
|
||||
export const APPS_STORAGE_KEY = 'APPS_STORAGE_KEY'
|
||||
|
||||
|
@ -175,6 +176,17 @@ export const staticAppsList: Array<StaticAppInfo> = [
|
|||
},
|
||||
]
|
||||
|
||||
export const getAppsList = async (): Promise<AppData[]> => {
|
||||
let result
|
||||
try {
|
||||
result = await fetchSafeAppsList()
|
||||
} catch (error) {
|
||||
console.error('Could not fetch remote apps list', error)
|
||||
}
|
||||
|
||||
return result?.apps && result?.apps.length ? result.apps : staticAppsList
|
||||
}
|
||||
|
||||
export const getAppInfoFromOrigin = (origin: string): { url: string; name: string } | null => {
|
||||
try {
|
||||
return JSON.parse(origin)
|
||||
|
|
|
@ -25,6 +25,9 @@ export const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 5000
|
|||
export const ETHERSCAN_API_KEY = process.env.REACT_APP_ETHERSCAN_API_KEY
|
||||
export const EXCHANGE_RATE_URL = 'https://api.exchangeratesapi.io/latest'
|
||||
export const EXCHANGE_RATE_URL_FALLBACK = 'https://api.coinbase.com/v2/exchange-rates'
|
||||
export const SAFE_APPS_LIST_URL =
|
||||
process.env.REACT_APP_SAFE_APPS_LIST_URL ||
|
||||
'https://raw.githubusercontent.com/gnosis/safe-apps-list/main/public/gnosis-default.applist.json'
|
||||
export const IPFS_GATEWAY = process.env.REACT_APP_IPFS_GATEWAY
|
||||
export const SPENDING_LIMIT_MODULE_ADDRESS =
|
||||
process.env.REACT_APP_SPENDING_LIMIT_MODULE_ADDRESS || '0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134'
|
||||
|
|
Loading…
Reference in New Issue