Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
411cd1dc
Commit
411cd1dc
authored
Jan 17, 2024
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
address user ops
parent
d1d615e6
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
212 additions
and
124 deletions
+212
-124
resources.ts
lib/api/resources.ts
+7
-2
userOps.ts
stubs/userOps.ts
+7
-1
userOps.ts
types/api/userOps.ts
+5
-0
AddressUserOps.tsx
ui/address/AddressUserOps.tsx
+35
-0
Address.tsx
ui/pages/Address.tsx
+24
-2
UserOps.tsx
ui/pages/UserOps.tsx
+3
-37
TxUserOps.tsx
ui/tx/TxUserOps.tsx
+4
-45
UserOpsContent.tsx
ui/userOps/UserOpsContent.tsx
+66
-0
UserOpsListItem.tsx
ui/userOps/UserOpsListItem.tsx
+26
-16
UserOpsTable.tsx
ui/userOps/UserOpsTable.tsx
+12
-4
UserOpsTableItem.tsx
ui/userOps/UserOpsTableItem.tsx
+23
-17
No files found.
lib/api/resources.ts
View file @
411cd1dc
...
...
@@ -77,7 +77,7 @@ import type {
import
type
{
TxInterpretationResponse
}
from
'
types/api/txInterpretation
'
;
import
type
{
TTxsFilters
}
from
'
types/api/txsFilters
'
;
import
type
{
TxStateChanges
}
from
'
types/api/txStateChanges
'
;
import
type
{
UserOpsResponse
,
UserOp
,
UserOpsFilters
}
from
'
types/api/userOps
'
;
import
type
{
UserOpsResponse
,
UserOp
,
UserOpsFilters
,
UserOpsAccount
}
from
'
types/api/userOps
'
;
import
type
{
VerifiedContractsSorting
}
from
'
types/api/verifiedContracts
'
;
import
type
{
VisualizedContract
}
from
'
types/api/visualization
'
;
import
type
{
WithdrawalsResponse
,
WithdrawalsCounters
}
from
'
types/api/withdrawals
'
;
...
...
@@ -583,13 +583,17 @@ export const RESOURCES = {
// USER OPS
user_ops
:
{
path
:
'
/api/v2/proxy/account-abstraction/operations
'
,
filterFields
:
[
'
transaction_hash
'
as
const
],
filterFields
:
[
'
transaction_hash
'
as
const
,
'
sender
'
as
const
],
},
user_op
:
{
path
:
'
/api/v2/proxy/account-abstraction/operations/:hash
'
,
pathParams
:
[
'
hash
'
as
const
],
},
user_ops_account
:
{
path
:
'
/api/v2/proxy/account-abstraction/accounts/:hash
'
,
pathParams
:
[
'
hash
'
as
const
],
},
// CONFIGS
config_backend_version
:
{
...
...
@@ -768,6 +772,7 @@ Q extends 'domain_events' ? EnsDomainEventsResponse :
Q
extends
'
domains_lookup
'
?
EnsDomainLookupResponse
:
Q
extends
'
user_ops
'
?
UserOpsResponse
:
Q
extends
'
user_op
'
?
UserOp
:
Q
extends
'
user_ops_account
'
?
UserOpsAccount
:
never
;
/* eslint-enable @typescript-eslint/indent */
...
...
stubs/userOps.ts
View file @
411cd1dc
import
type
{
UserOpsItem
,
UserOp
}
from
'
types/api/userOps
'
;
import
type
{
UserOpsItem
,
UserOp
,
UserOpsAccount
}
from
'
types/api/userOps
'
;
export
const
USER_OPS_ITEM
:
UserOpsItem
=
{
hash
:
'
0xb94fab8f31f83001a23e20b2ce3cdcfb284c57a64b9a073e0e09c018bc701978
'
,
...
...
@@ -39,4 +39,10 @@ export const USER_OP: UserOp = {
sponsor_type
:
'
paymaster_sponsor
'
,
fee
:
'
17927001792700
'
,
timestamp
:
'
1704994440
'
,
user_logs_count
:
1
,
user_logs_start_index
:
2
,
};
export
const
USER_OPS_ACCOUNT
:
UserOpsAccount
=
{
total_ops
:
1
,
};
types/api/userOps.ts
View file @
411cd1dc
...
...
@@ -53,4 +53,9 @@ export type UserOp = {
export
type
UserOpsFilters
=
{
transaction_hash
?:
string
;
sender
?:
string
;
}
export
type
UserOpsAccount
=
{
total_ops
:
number
;
}
ui/address/AddressUserOps.tsx
0 → 100644
View file @
411cd1dc
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
{
USER_OPS_ITEM
}
from
'
stubs/userOps
'
;
import
{
generateListStub
}
from
'
stubs/utils
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
UserOpsContent
from
'
ui/userOps/UserOpsContent
'
;
type
Props
=
{
scrollRef
?:
React
.
RefObject
<
HTMLDivElement
>
;
}
const
AddressUserOps
=
({
scrollRef
}:
Props
)
=>
{
const
router
=
useRouter
();
const
hash
=
getQueryParamString
(
router
.
query
.
hash
);
const
userOpsQuery
=
useQueryWithPages
({
resourceName
:
'
user_ops
'
,
scrollRef
,
options
:
{
enabled
:
Boolean
(
hash
),
placeholderData
:
generateListStub
<
'
user_ops
'
>
(
USER_OPS_ITEM
,
50
,
{
next_page_params
:
{
page_token
:
'
10355938,0x5956a847d8089e254e02e5111cad6992b99ceb9e5c2dc4343fd53002834c4dc6
'
,
page_size
:
50
,
}
}),
},
filters
:
{
sender
:
hash
},
});
return
<
UserOpsContent
query=
{
userOpsQuery
}
showSender=
{
false
}
/>;
};
export
default
AddressUserOps
;
ui/pages/Address.tsx
View file @
411cd1dc
...
...
@@ -11,6 +11,7 @@ import useContractTabs from 'lib/hooks/useContractTabs';
import
useIsSafeAddress
from
'
lib/hooks/useIsSafeAddress
'
;
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
{
ADDRESS_INFO
,
ADDRESS_TABS_COUNTERS
}
from
'
stubs/address
'
;
import
{
USER_OPS_ACCOUNT
}
from
'
stubs/userOps
'
;
import
AddressBlocksValidated
from
'
ui/address/AddressBlocksValidated
'
;
import
AddressCoinBalance
from
'
ui/address/AddressCoinBalance
'
;
import
AddressContract
from
'
ui/address/AddressContract
'
;
...
...
@@ -20,6 +21,7 @@ import AddressLogs from 'ui/address/AddressLogs';
import
AddressTokens
from
'
ui/address/AddressTokens
'
;
import
AddressTokenTransfers
from
'
ui/address/AddressTokenTransfers
'
;
import
AddressTxs
from
'
ui/address/AddressTxs
'
;
import
AddressUserOps
from
'
ui/address/AddressUserOps
'
;
import
AddressWithdrawals
from
'
ui/address/AddressWithdrawals
'
;
import
AddressFavoriteButton
from
'
ui/address/details/AddressFavoriteButton
'
;
import
AddressQrCode
from
'
ui/address/details/AddressQrCode
'
;
...
...
@@ -62,6 +64,14 @@ const AddressPageContent = () => {
},
});
const
userOpsAccountQuery
=
useApiQuery
(
'
user_ops_account
'
,
{
pathParams
:
{
hash
},
queryOptions
:
{
enabled
:
Boolean
(
hash
),
placeholderData
:
USER_OPS_ACCOUNT
,
},
});
const
isSafeAddress
=
useIsSafeAddress
(
!
addressQuery
.
isPlaceholderData
&&
addressQuery
.
data
?.
is_contract
?
hash
:
undefined
);
const
contractTabs
=
useContractTabs
(
addressQuery
.
data
);
...
...
@@ -74,6 +84,14 @@ const AddressPageContent = () => {
count
:
addressTabsCountersQuery
.
data
?.
transactions_count
,
component
:
<
AddressTxs
scrollRef=
{
tabsScrollRef
}
/>,
},
config
.
features
.
userOps
.
isEnabled
&&
Boolean
(
userOpsAccountQuery
.
data
?.
total_ops
)
?
{
id
:
'
user_ops
'
,
title
:
'
User operations
'
,
count
:
userOpsAccountQuery
.
data
?.
total_ops
,
component
:
<
AddressUserOps
/>,
}
:
undefined
,
config
.
features
.
beaconChain
.
isEnabled
&&
addressTabsCountersQuery
.
data
?.
withdrawals_count
?
{
id
:
'
withdrawals
'
,
...
...
@@ -140,7 +158,7 @@ const AddressPageContent = () => {
subTabs
:
contractTabs
.
map
(
tab
=>
tab
.
id
),
}
:
undefined
,
].
filter
(
Boolean
);
},
[
addressQuery
.
data
,
contractTabs
,
addressTabsCountersQuery
.
data
]);
},
[
addressQuery
.
data
,
contractTabs
,
addressTabsCountersQuery
.
data
,
userOpsAccountQuery
.
data
]);
const
tags
=
(
<
EntityTags
...
...
@@ -151,6 +169,7 @@ const AddressPageContent = () => {
addressQuery
.
data
?.
implementation_address
?
{
label
:
'
proxy
'
,
display_name
:
'
Proxy
'
}
:
undefined
,
addressQuery
.
data
?.
token
?
{
label
:
'
token
'
,
display_name
:
'
Token
'
}
:
undefined
,
isSafeAddress
?
{
label
:
'
safe
'
,
display_name
:
'
Multisig: Safe
'
}
:
undefined
,
userOpsAccountQuery
.
data
?.
total_ops
?
{
label
:
'
user_ops_acc
'
,
display_name
:
'
Smart contract wallet
'
}
:
undefined
,
]
}
/>
);
...
...
@@ -222,7 +241,10 @@ const AddressPageContent = () => {
<
AddressDetails
addressQuery=
{
addressQuery
}
scrollRef=
{
tabsScrollRef
}
/>
{
/* should stay before tabs to scroll up with pagination */
}
<
Box
ref=
{
tabsScrollRef
}
></
Box
>
{
(
addressQuery
.
isPlaceholderData
||
addressTabsCountersQuery
.
isPlaceholderData
)
?
<
TabsSkeleton
tabs=
{
tabs
}
/>
:
content
}
{
(
addressQuery
.
isPlaceholderData
||
addressTabsCountersQuery
.
isPlaceholderData
||
userOpsAccountQuery
.
isPlaceholderData
)
?
<
TabsSkeleton
tabs=
{
tabs
}
/>
:
content
}
</>
);
};
...
...
ui/pages/UserOps.tsx
View file @
411cd1dc
import
{
Hide
,
Show
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
{
USER_OPS_ITEM
}
from
'
stubs/userOps
'
;
import
{
generateListStub
}
from
'
stubs/utils
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
UserOpsListItem
from
'
ui/userOps/UserOpsListItem
'
;
import
UserOpsTable
from
'
ui/userOps/UserOpsTable
'
;
import
UserOpsContent
from
'
ui/userOps/UserOpsContent
'
;
const
UserOps
=
()
=>
{
const
{
data
,
isError
,
isPlaceholderData
,
pagination
}
=
useQueryWithPages
({
const
query
=
useQueryWithPages
({
resourceName
:
'
user_ops
'
,
options
:
{
placeholderData
:
generateListStub
<
'
user_ops
'
>
(
USER_OPS_ITEM
,
50
,
{
next_page_params
:
{
...
...
@@ -22,39 +17,10 @@ const UserOps = () => {
},
});
const
content
=
data
?.
items
?
(
<>
<
Show
below=
"lg"
ssr=
{
false
}
>
{
data
.
items
.
map
(((
item
,
index
)
=>
(
<
UserOpsListItem
key=
{
item
.
hash
+
(
isPlaceholderData
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
isPlaceholderData
}
/>
)))
}
</
Show
>
<
Hide
below=
"lg"
ssr=
{
false
}
>
<
UserOpsTable
items=
{
data
.
items
}
top=
{
pagination
.
isVisible
?
80
:
0
}
isLoading=
{
isPlaceholderData
}
/>
</
Hide
>
</>
)
:
null
;
const
actionBar
=
pagination
.
isVisible
?
(
<
ActionBar
mt=
{
-
6
}
alignItems=
"center"
>
<
Pagination
ml=
"auto"
{
...
pagination
}
/>
</
ActionBar
>
)
:
null
;
return
(
<>
<
PageTitle
title=
"User operations"
withTextAd
/>
<
DataListDisplay
isError=
{
isError
}
items=
{
data
?.
items
}
emptyText=
"There are no user operations."
content=
{
content
}
actionBar=
{
actionBar
}
/>
<
UserOpsContent
query=
{
query
}
/>
</>
);
};
...
...
ui/tx/TxUserOps.tsx
View file @
411cd1dc
import
{
Hide
,
Show
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
{
SECOND
}
from
'
lib/consts
'
;
import
{
USER_OPS_ITEM
}
from
'
stubs/userOps
'
;
import
{
generateListStub
}
from
'
stubs/utils
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
TxPendingAlert
from
'
ui/tx/TxPendingAlert
'
;
import
TxSocketAlert
from
'
ui/tx/TxSocketAlert
'
;
import
useFetchTxInfo
from
'
ui/tx/useFetchTxInfo
'
;
import
UserOpsListItem
from
'
ui/userOps/UserOpsListItem
'
;
import
UserOpsTable
from
'
ui/userOps/UserOpsTable
'
;
import
UserOpsContent
from
'
ui/userOps/UserOpsContent
'
;
const
Tx
TokenTransfer
=
()
=>
{
const
Tx
UserOps
=
()
=>
{
const
txsInfo
=
useFetchTxInfo
({
updateDelay
:
5
*
SECOND
});
const
userOpsQuery
=
useQueryWithPages
({
...
...
@@ -32,42 +26,7 @@ const TxTokenTransfer = () => {
return
txsInfo
.
socketStatus
?
<
TxSocketAlert
status=
{
txsInfo
.
socketStatus
}
/>
:
<
TxPendingAlert
/>;
}
if
(
txsInfo
.
isError
||
userOpsQuery
.
isError
)
{
return
<
DataFetchAlert
/>;
}
const
content
=
userOpsQuery
.
data
?.
items
?
(
<>
<
Hide
below=
"lg"
ssr=
{
false
}
>
<
UserOpsTable
items=
{
userOpsQuery
.
data
?.
items
}
top=
{
userOpsQuery
.
pagination
.
isVisible
?
0
:
80
}
isLoading=
{
userOpsQuery
.
isPlaceholderData
}
/>
</
Hide
>
<
Show
below=
"lg"
ssr=
{
false
}
>
{
userOpsQuery
.
data
.
items
.
map
(((
item
,
index
)
=>
(
<
UserOpsListItem
key=
{
item
.
hash
+
(
userOpsQuery
.
isPlaceholderData
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
userOpsQuery
.
isPlaceholderData
}
/>
)))
}
</
Show
>
</>
)
:
null
;
const
actionBar
=
userOpsQuery
.
pagination
.
isVisible
?
(
<
ActionBar
mt=
{
-
6
}
alignItems=
"center"
>
<
Pagination
ml=
"auto"
{
...
userOpsQuery
.
pagination
}
/>
</
ActionBar
>
)
:
null
;
return
(
<
DataListDisplay
isError=
{
txsInfo
.
isError
||
userOpsQuery
.
isError
}
items=
{
userOpsQuery
.
data
?.
items
}
emptyText=
"There are no user operations."
content=
{
content
}
actionBar=
{
actionBar
}
/>
);
return
<
UserOpsContent
query=
{
userOpsQuery
}
showTx=
{
false
}
/>;
};
export
default
Tx
TokenTransfer
;
export
default
Tx
UserOps
;
ui/userOps/UserOpsContent.tsx
0 → 100644
View file @
411cd1dc
import
{
Hide
,
Show
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
type
{
QueryWithPagesResult
}
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
UserOpsListItem
from
'
ui/userOps/UserOpsListItem
'
;
import
UserOpsTable
from
'
ui/userOps/UserOpsTable
'
;
type
Props
=
{
query
:
QueryWithPagesResult
<
'
user_ops
'
>
;
showTx
?:
boolean
;
showSender
?:
boolean
;
};
const
UserOpsContent
=
({
query
,
showTx
=
true
,
showSender
=
true
}:
Props
)
=>
{
if
(
query
.
isError
)
{
return
<
DataFetchAlert
/>;
}
const
content
=
query
.
data
?.
items
?
(
<>
<
Hide
below=
"lg"
ssr=
{
false
}
>
<
UserOpsTable
items=
{
query
.
data
.
items
}
top=
{
query
.
pagination
.
isVisible
?
0
:
80
}
isLoading=
{
query
.
isPlaceholderData
}
showTx=
{
showTx
}
showSender=
{
showSender
}
/>
</
Hide
>
<
Show
below=
"lg"
ssr=
{
false
}
>
{
query
.
data
.
items
.
map
(((
item
,
index
)
=>
(
<
UserOpsListItem
key=
{
item
.
hash
+
(
query
.
isPlaceholderData
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
query
.
isPlaceholderData
}
showTx=
{
showTx
}
showSender=
{
showSender
}
/>
)))
}
</
Show
>
</>
)
:
null
;
const
actionBar
=
query
.
pagination
.
isVisible
?
(
<
ActionBar
mt=
{
-
6
}
alignItems=
"center"
>
<
Pagination
ml=
"auto"
{
...
query
.
pagination
}
/>
</
ActionBar
>
)
:
null
;
return
(
<
DataListDisplay
isError=
{
query
.
isError
}
items=
{
query
.
data
?.
items
}
emptyText=
"There are no user operations."
content=
{
content
}
actionBar=
{
actionBar
}
/>
);
};
export
default
UserOpsContent
;
ui/userOps/UserOpsListItem.tsx
View file @
411cd1dc
...
...
@@ -16,9 +16,11 @@ import UserOpStatus from 'ui/shared/userOps/UserOpStatus';
type
Props
=
{
item
:
UserOpsItem
;
isLoading
?:
boolean
;
showTx
:
boolean
;
showSender
:
boolean
;
};
const
UserOpsListItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
UserOpsListItem
=
({
item
,
isLoading
,
showTx
,
showSender
}:
Props
)
=>
{
// format will be fixed on the back-end
const
timeAgo
=
dayjs
(
Number
(
item
.
timestamp
)
*
1000
).
fromNow
();
...
...
@@ -40,22 +42,30 @@ const UserOpsListItem = ({ item, isLoading }: Props) => {
<
UserOpStatus
status=
{
item
.
status
}
isLoading=
{
isLoading
}
/>
</
ListItemMobileGrid
.
Value
>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Sender
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
<
UserOpsAddress
address=
{
item
.
address
}
isLoading=
{
isLoading
}
/>
</
ListItemMobileGrid
.
Value
>
{
showSender
&&
(
<>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Sender
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
<
UserOpsAddress
address=
{
item
.
address
}
isLoading=
{
isLoading
}
/>
</
ListItemMobileGrid
.
Value
>
</>
)
}
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Tx hash
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
<
TxEntity
hash=
{
item
.
transaction_hash
}
isLoading=
{
isLoading
}
noIcon
/>
</
ListItemMobileGrid
.
Value
>
{
showTx
&&
(
<>
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Tx hash
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
<
TxEntity
hash=
{
item
.
transaction_hash
}
isLoading=
{
isLoading
}
noIcon
/>
</
ListItemMobileGrid
.
Value
>
</>
)
}
<
ListItemMobileGrid
.
Label
isLoading=
{
isLoading
}
>
Block
</
ListItemMobileGrid
.
Label
>
<
ListItemMobileGrid
.
Value
>
...
...
ui/userOps/UserOpsTable.tsx
View file @
411cd1dc
...
...
@@ -12,9 +12,11 @@ import UserOpsTableItem from './UserOpsTableItem';
items
:
Array
<
UserOpsItem
>
;
isLoading
?:
boolean
;
top
:
number
;
showTx
:
boolean
;
showSender
:
boolean
;
};
const
UserOpsTable
=
({
items
,
isLoading
,
top
}:
Props
)
=>
{
const
UserOpsTable
=
({
items
,
isLoading
,
top
,
showTx
,
showSender
}:
Props
)
=>
{
return
(
<
Table
variant=
"simple"
size=
"sm"
>
<
Thead
top=
{
top
}
>
...
...
@@ -22,15 +24,21 @@ const UserOpsTable = ({ items, isLoading, top }: Props) => {
<
Th
w=
"60%"
>
User op hash
</
Th
>
<
Th
w=
"110px"
>
Age
</
Th
>
<
Th
w=
"140px"
>
Status
</
Th
>
<
Th
w=
"160px"
>
Sender
</
Th
>
<
Th
w=
"160px"
>
Tx hash
</
Th
>
{
showSender
&&
<
Th
w=
"160px"
>
Sender
</
Th
>
}
{
showTx
&&
<
Th
w=
"160px"
>
Tx hash
</
Th
>
}
<
Th
w=
"40%"
>
Block
</
Th
>
{
!
config
.
UI
.
views
.
tx
.
hiddenFields
?.
tx_fee
&&
<
Th
w=
"120px"
isNumeric
>
{
`Fee ${ config.chain.currency.symbol }`
}
</
Th
>
}
</
Tr
>
</
Thead
>
<
Tbody
>
{
items
.
map
((
item
,
index
)
=>
(
<
UserOpsTableItem
key=
{
(
isLoading
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
isLoading
}
/>
<
UserOpsTableItem
key=
{
(
isLoading
?
String
(
index
)
:
''
)
}
item=
{
item
}
isLoading=
{
isLoading
}
showSender=
{
showSender
}
showTx=
{
showTx
}
/>
))
}
</
Tbody
>
</
Table
>
...
...
ui/userOps/UserOpsTableItem.tsx
View file @
411cd1dc
...
...
@@ -15,9 +15,11 @@ import UserOpStatus from 'ui/shared/userOps/UserOpStatus';
type
Props
=
{
item
:
UserOpsItem
;
isLoading
?:
boolean
;
showTx
:
boolean
;
showSender
:
boolean
;
};
const
WithdrawalsTableItem
=
({
item
,
isLoading
}:
Props
)
=>
{
const
UserOpsTableItem
=
({
item
,
isLoading
,
showTx
,
showSender
}:
Props
)
=>
{
// will be fixed on the back-end
const
timeAgo
=
dayjs
(
Number
(
item
.
timestamp
)
*
1000
).
fromNow
();
...
...
@@ -32,21 +34,25 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
<
Td
verticalAlign=
"middle"
>
<
UserOpStatus
status=
{
item
.
status
}
isLoading=
{
isLoading
}
/>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
UserOpsAddress
address=
{
item
.
address
}
isLoading=
{
isLoading
}
truncation=
"constant"
/>
</
Td
>
<
Td
verticalAlign=
"middle"
>
<
TxEntity
hash=
{
item
.
transaction_hash
}
isLoading=
{
isLoading
}
truncation=
"constant"
noIcon
/>
</
Td
>
{
showSender
&&
(
<
Td
verticalAlign=
"middle"
>
<
UserOpsAddress
address=
{
item
.
address
}
isLoading=
{
isLoading
}
truncation=
"constant"
/>
</
Td
>
)
}
{
showTx
&&
(
<
Td
verticalAlign=
"middle"
>
<
TxEntity
hash=
{
item
.
transaction_hash
}
isLoading=
{
isLoading
}
truncation=
"constant"
noIcon
/>
</
Td
>
)
}
<
Td
verticalAlign=
"middle"
>
<
BlockEntity
number=
{
item
.
block_number
}
...
...
@@ -65,4 +71,4 @@ const WithdrawalsTableItem = ({ item, isLoading }: Props) => {
);
};
export
default
Withdrawal
sTableItem
;
export
default
UserOp
sTableItem
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment