Adding Apps info to toast notification (#621)
* Adding APP_Name for APPs TXs in toast messages * refactor: save appId instead of appName in origin field * adding fallback icon and message to TX apps table * review changes * review fixes * force build
This commit is contained in:
parent
0037522505
commit
63252566dc
|
@ -7,6 +7,7 @@ import { NOTIFICATIONS, type Notification } from './notificationTypes'
|
||||||
|
|
||||||
import closeSnackbarAction from '~/logic/notifications/store/actions/closeSnackbar'
|
import closeSnackbarAction from '~/logic/notifications/store/actions/closeSnackbar'
|
||||||
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
||||||
|
import { getAppInfo } from '~/routes/safe/components/Apps/appsList'
|
||||||
import { store } from '~/store'
|
import { store } from '~/store'
|
||||||
|
|
||||||
export type NotificationsQueue = {
|
export type NotificationsQueue = {
|
||||||
|
@ -21,15 +22,26 @@ export type NotificationsQueue = {
|
||||||
afterRejection: Notification | null,
|
afterRejection: Notification | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const standardTxNotificationsQueue: NotificationsQueue = {
|
const setNotificationOrigin = (notification: Notification, origin: string): Notification => {
|
||||||
beforeExecution: NOTIFICATIONS.SIGN_TX_MSG,
|
if (!origin) {
|
||||||
pendingExecution: NOTIFICATIONS.TX_PENDING_MSG,
|
return notification
|
||||||
afterRejection: NOTIFICATIONS.TX_REJECTED_MSG,
|
}
|
||||||
afterExecution: {
|
|
||||||
noMoreConfirmationsNeeded: NOTIFICATIONS.TX_EXECUTED_MSG,
|
const appInfo = getAppInfo(origin)
|
||||||
moreConfirmationsNeeded: NOTIFICATIONS.TX_EXECUTED_MORE_CONFIRMATIONS_MSG,
|
return { ...notification, message: `${appInfo.name}: ${notification.message}` }
|
||||||
},
|
}
|
||||||
afterExecutionError: NOTIFICATIONS.TX_FAILED_MSG,
|
|
||||||
|
const getStandardTxNotificationsQueue = (origin?: string): NotificationsQueue => {
|
||||||
|
return {
|
||||||
|
beforeExecution: setNotificationOrigin(NOTIFICATIONS.SIGN_TX_MSG, origin),
|
||||||
|
pendingExecution: setNotificationOrigin(NOTIFICATIONS.TX_PENDING_MSG, origin),
|
||||||
|
afterRejection: setNotificationOrigin(NOTIFICATIONS.TX_REJECTED_MSG, origin),
|
||||||
|
afterExecution: {
|
||||||
|
noMoreConfirmationsNeeded: setNotificationOrigin(NOTIFICATIONS.TX_EXECUTED_MSG, origin),
|
||||||
|
moreConfirmationsNeeded: setNotificationOrigin(NOTIFICATIONS.TX_EXECUTED_MORE_CONFIRMATIONS_MSG, origin),
|
||||||
|
},
|
||||||
|
afterExecutionError: setNotificationOrigin(NOTIFICATIONS.TX_FAILED_MSG, origin),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitingTransactionNotificationsQueue: NotificationsQueue = {
|
const waitingTransactionNotificationsQueue: NotificationsQueue = {
|
||||||
|
@ -41,26 +53,30 @@ const waitingTransactionNotificationsQueue: NotificationsQueue = {
|
||||||
afterExecutionError: null,
|
afterExecutionError: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmationTxNotificationsQueue: NotificationsQueue = {
|
const getConfirmationTxNotificationsQueue = (origin?: string): NotificationsQueue => {
|
||||||
beforeExecution: NOTIFICATIONS.SIGN_TX_MSG,
|
return {
|
||||||
pendingExecution: NOTIFICATIONS.TX_CONFIRMATION_PENDING_MSG,
|
beforeExecution: setNotificationOrigin(NOTIFICATIONS.SIGN_TX_MSG, origin),
|
||||||
afterRejection: NOTIFICATIONS.TX_REJECTED_MSG,
|
pendingExecution: setNotificationOrigin(NOTIFICATIONS.TX_CONFIRMATION_PENDING_MSG, origin),
|
||||||
afterExecution: {
|
afterRejection: setNotificationOrigin(NOTIFICATIONS.TX_REJECTED_MSG, origin),
|
||||||
noMoreConfirmationsNeeded: NOTIFICATIONS.TX_EXECUTED_MSG,
|
afterExecution: {
|
||||||
moreConfirmationsNeeded: NOTIFICATIONS.TX_CONFIRMATION_EXECUTED_MSG,
|
noMoreConfirmationsNeeded: setNotificationOrigin(NOTIFICATIONS.TX_EXECUTED_MSG, origin),
|
||||||
},
|
moreConfirmationsNeeded: setNotificationOrigin(NOTIFICATIONS.TX_CONFIRMATION_EXECUTED_MSG, origin),
|
||||||
afterExecutionError: NOTIFICATIONS.TX_CONFIRMATION_FAILED_MSG,
|
},
|
||||||
|
afterExecutionError: setNotificationOrigin(NOTIFICATIONS.TX_CONFIRMATION_FAILED_MSG, origin),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancellationTxNotificationsQueue: NotificationsQueue = {
|
const getCancellationTxNotificationsQueue = (origin?: string): NotificationsQueue => {
|
||||||
beforeExecution: NOTIFICATIONS.SIGN_TX_MSG,
|
return {
|
||||||
pendingExecution: NOTIFICATIONS.TX_PENDING_MSG,
|
beforeExecution: setNotificationOrigin(NOTIFICATIONS.SIGN_TX_MSG, origin),
|
||||||
afterRejection: NOTIFICATIONS.TX_REJECTED_MSG,
|
pendingExecution: setNotificationOrigin(NOTIFICATIONS.TX_PENDING_MSG, origin),
|
||||||
afterExecution: {
|
afterRejection: setNotificationOrigin(NOTIFICATIONS.TX_REJECTED_MSG, origin),
|
||||||
noMoreConfirmationsNeeded: NOTIFICATIONS.TX_EXECUTED_MSG,
|
afterExecution: {
|
||||||
moreConfirmationsNeeded: NOTIFICATIONS.TX_CANCELLATION_EXECUTED_MSG,
|
noMoreConfirmationsNeeded: setNotificationOrigin(NOTIFICATIONS.TX_EXECUTED_MSG, origin),
|
||||||
},
|
moreConfirmationsNeeded: setNotificationOrigin(NOTIFICATIONS.TX_CANCELLATION_EXECUTED_MSG, origin),
|
||||||
afterExecutionError: NOTIFICATIONS.TX_FAILED_MSG,
|
},
|
||||||
|
afterExecutionError: setNotificationOrigin(NOTIFICATIONS.TX_FAILED_MSG, origin),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeNameChangeNotificationsQueue: NotificationsQueue = {
|
const safeNameChangeNotificationsQueue: NotificationsQueue = {
|
||||||
|
@ -143,20 +159,20 @@ const addressBookDeleteEntry: NotificationsQueue = {
|
||||||
afterExecutionError: null,
|
afterExecutionError: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getNotificationsFromTxType = (txType: string) => {
|
export const getNotificationsFromTxType = (txType: string, origin?: string) => {
|
||||||
let notificationsQueue: NotificationsQueue
|
let notificationsQueue: NotificationsQueue
|
||||||
|
|
||||||
switch (txType) {
|
switch (txType) {
|
||||||
case TX_NOTIFICATION_TYPES.STANDARD_TX: {
|
case TX_NOTIFICATION_TYPES.STANDARD_TX: {
|
||||||
notificationsQueue = standardTxNotificationsQueue
|
notificationsQueue = getStandardTxNotificationsQueue(origin)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case TX_NOTIFICATION_TYPES.CONFIRMATION_TX: {
|
case TX_NOTIFICATION_TYPES.CONFIRMATION_TX: {
|
||||||
notificationsQueue = confirmationTxNotificationsQueue
|
notificationsQueue = getConfirmationTxNotificationsQueue(origin)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case TX_NOTIFICATION_TYPES.CANCELLATION_TX: {
|
case TX_NOTIFICATION_TYPES.CANCELLATION_TX: {
|
||||||
notificationsQueue = cancellationTxNotificationsQueue
|
notificationsQueue = getCancellationTxNotificationsQueue(origin)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX: {
|
case TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX: {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import appsIconSvg from '../Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
||||||
|
|
||||||
const appList = [
|
const appList = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: '1',
|
||||||
name: 'Compound',
|
name: 'Compound',
|
||||||
url: process.env.REACT_APP_GNOSIS_APPS_URL || 'https://gnosis-apps.netlify.com',
|
url: process.env.REACT_APP_GNOSIS_APPS_URL || 'https://gnosis-apps.netlify.com',
|
||||||
iconUrl: 'https://compound.finance/images/compound-mark.svg',
|
iconUrl: 'https://compound.finance/images/compound-mark.svg',
|
||||||
|
@ -9,7 +11,7 @@ const appList = [
|
||||||
providedBy: { name: 'Gnosis', url: '' },
|
providedBy: { name: 'Gnosis', url: '' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: '2',
|
||||||
name: 'ENS Manager',
|
name: 'ENS Manager',
|
||||||
url: '',
|
url: '',
|
||||||
iconUrl: 'https://app.ens.domains/static/media/ensIconLogo.4d995d23.svg',
|
iconUrl: 'https://app.ens.domains/static/media/ensIconLogo.4d995d23.svg',
|
||||||
|
@ -17,7 +19,7 @@ const appList = [
|
||||||
providedBy: { name: 'Gnosis', url: '' },
|
providedBy: { name: 'Gnosis', url: '' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: '3',
|
||||||
name: 'Uniswap',
|
name: 'Uniswap',
|
||||||
url: '',
|
url: '',
|
||||||
iconUrl:
|
iconUrl:
|
||||||
|
@ -26,7 +28,7 @@ const appList = [
|
||||||
providedBy: { name: 'Gnosis', url: '' },
|
providedBy: { name: 'Gnosis', url: '' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: '4',
|
||||||
name: 'Nexus Mutual',
|
name: 'Nexus Mutual',
|
||||||
url: '',
|
url: '',
|
||||||
iconUrl:
|
iconUrl:
|
||||||
|
@ -41,4 +43,20 @@ const appList = [
|
||||||
|
|
||||||
export default appList
|
export default appList
|
||||||
|
|
||||||
export const getAppInfo = (appName: string) => appList.find(app => app.name === appName)
|
export const getAppInfo = (appId: string) => {
|
||||||
|
const res = appList.find(app => app.id === appId.toString())
|
||||||
|
if (!res) {
|
||||||
|
return {
|
||||||
|
id: 0,
|
||||||
|
name: 'External App',
|
||||||
|
url: null,
|
||||||
|
iconUrl: appsIconSvg,
|
||||||
|
description: null,
|
||||||
|
providedBy: {
|
||||||
|
name: null,
|
||||||
|
url: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import { withSnackbar } from 'notistack'
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import ButtonLink from '../../../../components/layout/ButtonLink'
|
|
||||||
|
|
||||||
import appsList from './appsList'
|
import appsList from './appsList'
|
||||||
import confirmTransactions from './confirmTransactions'
|
import confirmTransactions from './confirmTransactions'
|
||||||
import sendTransactions from './sendTransactions'
|
import sendTransactions from './sendTransactions'
|
||||||
|
|
||||||
import { ListContentLayout as LCL, Loader } from '~/components-v2'
|
import { ListContentLayout as LCL, Loader } from '~/components-v2'
|
||||||
|
import ButtonLink from '~/components/layout/ButtonLink'
|
||||||
|
|
||||||
const StyledIframe = styled.iframe`
|
const StyledIframe = styled.iframe`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -29,12 +29,25 @@ type Props = {
|
||||||
ethBalance: String,
|
ethBalance: String,
|
||||||
network: String,
|
network: String,
|
||||||
createTransaction: any,
|
createTransaction: any,
|
||||||
|
enqueueSnackbar: Function,
|
||||||
|
closeSnackbar: Function,
|
||||||
openModal: () => {},
|
openModal: () => {},
|
||||||
closeModal: () => {},
|
closeModal: () => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
function Apps({ closeModal, createTransaction, ethBalance, network, openModal, safeAddress, safeName, web3 }: Props) {
|
function Apps({
|
||||||
const [selectedApp, setSelectedApp] = useState(1)
|
closeModal,
|
||||||
|
closeSnackbar,
|
||||||
|
createTransaction,
|
||||||
|
enqueueSnackbar,
|
||||||
|
ethBalance,
|
||||||
|
network,
|
||||||
|
openModal,
|
||||||
|
safeAddress,
|
||||||
|
safeName,
|
||||||
|
web3,
|
||||||
|
}: Props) {
|
||||||
|
const [selectedApp, setSelectedApp] = useState('1')
|
||||||
const [appIsLoading, setAppIsLoading] = useState(true)
|
const [appIsLoading, setAppIsLoading] = useState(true)
|
||||||
const [iframeEl, setframeEl] = useState(null)
|
const [iframeEl, setframeEl] = useState(null)
|
||||||
|
|
||||||
|
@ -55,7 +68,15 @@ function Apps({ closeModal, createTransaction, ethBalance, network, openModal, s
|
||||||
const onConfirm = async () => {
|
const onConfirm = async () => {
|
||||||
closeModal()
|
closeModal()
|
||||||
|
|
||||||
const txHash = await sendTransactions(web3, createTransaction, safeAddress, data.data, getSelectedApp().name)
|
const txHash = await sendTransactions(
|
||||||
|
web3,
|
||||||
|
createTransaction,
|
||||||
|
safeAddress,
|
||||||
|
data.data,
|
||||||
|
enqueueSnackbar,
|
||||||
|
closeSnackbar,
|
||||||
|
getSelectedApp().id,
|
||||||
|
)
|
||||||
|
|
||||||
if (txHash) {
|
if (txHash) {
|
||||||
sendMessageToIframe(operations.ON_TX_UPDATE, {
|
sendMessageToIframe(operations.ON_TX_UPDATE, {
|
||||||
|
@ -184,4 +205,4 @@ function Apps({ closeModal, createTransaction, ethBalance, network, openModal, s
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Apps
|
export default withSnackbar(Apps)
|
||||||
|
|
|
@ -14,7 +14,15 @@ const multiSendAbi = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const sendTransactions = (web3: any, createTransaction: any, safeAddress: String, txs: Array<any>, origin: string) => {
|
const sendTransactions = (
|
||||||
|
web3: any,
|
||||||
|
createTransaction: any,
|
||||||
|
safeAddress: String,
|
||||||
|
txs: Array<any>,
|
||||||
|
enqueueSnackbar: Function,
|
||||||
|
closeSnackbar: Function,
|
||||||
|
origin: string,
|
||||||
|
) => {
|
||||||
const multiSend = new web3.eth.Contract(multiSendAbi, multiSendAddress)
|
const multiSend = new web3.eth.Contract(multiSendAbi, multiSendAddress)
|
||||||
|
|
||||||
const encodeMultiSendCalldata = multiSend.methods
|
const encodeMultiSendCalldata = multiSend.methods
|
||||||
|
@ -39,8 +47,8 @@ const sendTransactions = (web3: any, createTransaction: any, safeAddress: String
|
||||||
valueInWei: 0,
|
valueInWei: 0,
|
||||||
txData: encodeMultiSendCalldata,
|
txData: encodeMultiSendCalldata,
|
||||||
notifiedTransaction: 'STANDARD_TX',
|
notifiedTransaction: 'STANDARD_TX',
|
||||||
enqueueSnackbar: () => {},
|
enqueueSnackbar,
|
||||||
closeSnackbar: () => {},
|
closeSnackbar,
|
||||||
operation: DELEGATE_CALL,
|
operation: DELEGATE_CALL,
|
||||||
navigateToTransactionsTab: false,
|
navigateToTransactionsTab: false,
|
||||||
origin,
|
origin,
|
||||||
|
|
|
@ -74,6 +74,7 @@ const RejectTxModal = ({
|
||||||
enqueueSnackbar,
|
enqueueSnackbar,
|
||||||
closeSnackbar,
|
closeSnackbar,
|
||||||
txNonce: tx.nonce,
|
txNonce: tx.nonce,
|
||||||
|
origin: tx.origin,
|
||||||
})
|
})
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
|
||||||
|
<path
|
||||||
|
className="fill"
|
||||||
|
fillRule="nonzero"
|
||||||
|
d="M2 1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zm1 2v2h2V3H3zM10 9h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zm1 2v2h2v-2h-2zM12 7a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1.9a1.1 1.1 0 1 1 0-2.2 1.1 1.1 0 0 1 0 2.2z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
className="fill"
|
||||||
|
d="M2.641 11.999l-1.36-1.361A.96.96 0 0 1 2.637 9.28l1.36 1.36 1.362-1.36a.959.959 0 1 1 1.357 1.357l-1.36 1.36 1.36 1.362a.96.96 0 0 1-1.357 1.358L4 13.356l-1.361 1.362a.962.962 0 0 1-1.358 0 .964.964 0 0 1 0-1.358l1.361-1.361z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 690 B |
|
@ -31,7 +31,7 @@ const typeToLabel = {
|
||||||
|
|
||||||
const TxType = ({ txType, origin }: { txType: TransactionType, origin: string | null }) => {
|
const TxType = ({ txType, origin }: { txType: TransactionType, origin: string | null }) => {
|
||||||
const iconUrl = txType === 'third-party-app' ? getAppInfo(origin).iconUrl : typeToIcon[txType]
|
const iconUrl = txType === 'third-party-app' ? getAppInfo(origin).iconUrl : typeToIcon[txType]
|
||||||
const text = txType === 'third-party-app' ? origin : typeToLabel[txType]
|
const text = txType === 'third-party-app' ? getAppInfo(origin).name : typeToLabel[txType]
|
||||||
|
|
||||||
return <IconText iconUrl={iconUrl} text={text} />
|
return <IconText iconUrl={iconUrl} text={text} />
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ const createTransaction = ({
|
||||||
'',
|
'',
|
||||||
)}000000000000000000000000000000000000000000000000000000000000000001`
|
)}000000000000000000000000000000000000000000000000000000000000000001`
|
||||||
|
|
||||||
const notificationsQueue: NotificationsQueue = getNotificationsFromTxType(notifiedTransaction)
|
const notificationsQueue: NotificationsQueue = getNotificationsFromTxType(notifiedTransaction, origin)
|
||||||
const beforeExecutionKey = showSnackbar(notificationsQueue.beforeExecution, enqueueSnackbar, closeSnackbar)
|
const beforeExecutionKey = showSnackbar(notificationsQueue.beforeExecution, enqueueSnackbar, closeSnackbar)
|
||||||
let pendingExecutionKey
|
let pendingExecutionKey
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ const processTransaction = ({
|
||||||
)}000000000000000000000000000000000000000000000000000000000000000001`
|
)}000000000000000000000000000000000000000000000000000000000000000001`
|
||||||
}
|
}
|
||||||
|
|
||||||
const notificationsQueue: NotificationsQueue = getNotificationsFromTxType(notifiedTransaction)
|
const notificationsQueue: NotificationsQueue = getNotificationsFromTxType(notifiedTransaction, tx.origin)
|
||||||
const beforeExecutionKey = showSnackbar(notificationsQueue.beforeExecution, enqueueSnackbar, closeSnackbar)
|
const beforeExecutionKey = showSnackbar(notificationsQueue.beforeExecution, enqueueSnackbar, closeSnackbar)
|
||||||
let pendingExecutionKey
|
let pendingExecutionKey
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue