@stellar-expert/ui-framework 1.16.8 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1168 -3
- package/account/account-address.js +127 -127
- package/account/available-balance.js +22 -22
- package/account/identicon.js +90 -90
- package/account/signer-key.js +65 -64
- package/api/explorer-api-hooks.js +209 -202
- package/api/explorer-api-paginated-list-hooks.js +441 -440
- package/api/explorer-batch-info-loader.js +111 -85
- package/api/explorer-tx-api.js +28 -28
- package/api/ledger-stream.js +15 -0
- package/asset/amount.js +56 -56
- package/asset/asset-icon.js +41 -41
- package/asset/asset-issuer.js +21 -21
- package/asset/asset-link.js +107 -107
- package/asset/asset-list-hooks.js +59 -59
- package/asset/asset-meta-hooks.js +88 -88
- package/asset/asset-selector.js +72 -71
- package/claimable-balance/claimable-balance-claimants.js +23 -18
- package/contract/contract-api.js +15 -0
- package/contract/invocation-info-view.js +10 -2
- package/contract/sc-val.js +131 -107
- package/controls/button-group.js +25 -19
- package/controls/button.js +93 -78
- package/controls/code-block.js +42 -34
- package/controls/dropdown.js +318 -287
- package/controls/external-link.js +10 -4
- package/controls/info-tooltip.js +23 -16
- package/controls/slider.js +29 -19
- package/controls/tabs.js +94 -94
- package/controls/tooltip.js +244 -240
- package/controls/update-highlighter.js +32 -27
- package/date/date-selector.js +56 -54
- package/date/elapsed-time.js +28 -21
- package/dex/price-dynamic.js +53 -44
- package/directory/directory-hooks.js +109 -97
- package/effect/effect-description.js +346 -344
- package/errors/error-boundary.js +110 -97
- package/filter/editors/account-filter-view.js +20 -0
- package/filter/editors/asset-filter-view.js +9 -0
- package/filter/editors/timestamp-filter-view.js +34 -0
- package/filter/editors/type-filter-view.js +148 -0
- package/filter/filter-editors.js +102 -0
- package/filter/filter-view.js +218 -0
- package/filter/filter.scss +57 -0
- package/horizon/horizon-account-helpers.js +104 -104
- package/horizon/horizon-ledger-helpers.js +35 -35
- package/horizon/horizon-trades-helper.js +88 -88
- package/horizon/horizon-transaction-helpers.js +36 -36
- package/index.d.ts +1271 -0
- package/index.js +95 -93
- package/interaction/accordion.js +43 -35
- package/interaction/autofocus.js +13 -9
- package/interaction/block-select.js +64 -53
- package/interaction/copy-to-clipboard.js +25 -18
- package/interaction/inline-progress.js +20 -15
- package/interaction/qr-code.js +34 -34
- package/interaction/responsive.js +20 -20
- package/interaction/spoiler.js +52 -39
- package/interaction/theme-selector.js +13 -10
- package/ledger/ledger-entry-href-formatter.js +27 -26
- package/ledger/ledger-entry-link.js +93 -58
- package/ledger/ledger-info-parser.js +46 -18
- package/meta/page-meta-tags.js +243 -238
- package/module/dynamic-module.js +47 -47
- package/package.json +71 -40
- package/state/on-screen-hooks.js +22 -22
- package/state/page-visibility-helpers.js +29 -16
- package/state/page-visibility-hooks.js +13 -11
- package/state/screen-orientation-hooks.js +19 -15
- package/state/state-hooks.js +76 -76
- package/state/stellar-network-hooks.js +56 -44
- package/state/theme.js +29 -28
- package/stellar/key-type.js +92 -91
- package/stellar/ledger-generic-id.js +39 -39
- package/stellar/signature-hint-utils.js +65 -65
- package/toast/toast-notifications-block.js +59 -59
- package/tx/op-description-view.js +945 -942
- package/tx/op-icon.js +98 -98
- package/tx/parser/op-balance-changes.js +66 -66
- package/tx/parser/op-descriptor.js +51 -48
- package/tx/parser/tx-details-parser.js +81 -81
- package/tx/parser/tx-matcher.js +371 -371
- package/tx/parser/type-filter-matcher.js +126 -126
- package/tx/tx-list-hooks.js +32 -18
- package/tx/tx-operations-list.js +117 -116
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
const operationTypeMap = {
|
|
2
|
-
createAccount: 0,
|
|
3
|
-
payment: 1,
|
|
4
|
-
pathPaymentStrictReceive: 2,
|
|
5
|
-
pathPaymentStrictSend: 13,
|
|
6
|
-
createPassiveSellOffer: 4,
|
|
7
|
-
manageSellOffer: 3,
|
|
8
|
-
manageBuyOffer: 12,
|
|
9
|
-
setOptions: 5,
|
|
10
|
-
changeTrust: 6,
|
|
11
|
-
allowTrust: 7,
|
|
12
|
-
accountMerge: 8,
|
|
13
|
-
inflation: 9,
|
|
14
|
-
manageData: 10,
|
|
15
|
-
bumpSequence: 11,
|
|
16
|
-
createClaimableBalance: 14,
|
|
17
|
-
claimClaimableBalance: 15,
|
|
18
|
-
beginSponsoringFutureReserves: 16,
|
|
19
|
-
endSponsoringFutureReserves: 17,
|
|
20
|
-
revokeSponsorship: 18,
|
|
21
|
-
clawback: 19,
|
|
22
|
-
clawbackClaimableBalance: 20,
|
|
23
|
-
setTrustLineFlags: 21,
|
|
24
|
-
liquidityPoolDeposit: 22,
|
|
25
|
-
liquidityPoolWithdraw: 23,
|
|
26
|
-
invokeHostFunction: 24,
|
|
27
|
-
bumpFootprintExpiration: 25,
|
|
28
|
-
restoreFootprint: 26
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class TypeFilterMatcher {
|
|
32
|
-
/**
|
|
33
|
-
* @param {
|
|
34
|
-
*/
|
|
35
|
-
constructor(filters) {
|
|
36
|
-
if (!filters?.length)
|
|
37
|
-
return
|
|
38
|
-
this.types = new Set()
|
|
39
|
-
for (const filter of filters) {
|
|
40
|
-
this.processFilter(filter)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @type {Set}
|
|
46
|
-
* @readonly
|
|
47
|
-
* @private
|
|
48
|
-
*/
|
|
49
|
-
types
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Get unique set of type filters
|
|
53
|
-
* @return {
|
|
54
|
-
*/
|
|
55
|
-
match(operationType) {
|
|
56
|
-
return !this.types || this.types.has(operationTypeMap[operationType])
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @param {
|
|
61
|
-
* @private
|
|
62
|
-
*/
|
|
63
|
-
processFilter(filter) {
|
|
64
|
-
for (const type of this.decodeFilter(filter)) {
|
|
65
|
-
this.types.add(type)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @param {
|
|
71
|
-
* @private
|
|
72
|
-
*/
|
|
73
|
-
decodeFilter(filter) {
|
|
74
|
-
switch (filter) {
|
|
75
|
-
case 'payments':
|
|
76
|
-
return [
|
|
77
|
-
operationTypeMap.createAccount,
|
|
78
|
-
operationTypeMap.accountMerge,
|
|
79
|
-
operationTypeMap.payment,
|
|
80
|
-
operationTypeMap.pathPaymentStrictReceive,
|
|
81
|
-
operationTypeMap.pathPaymentStrictSend,
|
|
82
|
-
operationTypeMap.createClaimableBalance,
|
|
83
|
-
operationTypeMap.claimClaimableBalance,
|
|
84
|
-
operationTypeMap.clawback,
|
|
85
|
-
operationTypeMap.clawbackClaimableBalance,
|
|
86
|
-
operationTypeMap.inflation
|
|
87
|
-
]
|
|
88
|
-
case 'trustlines':
|
|
89
|
-
return [
|
|
90
|
-
operationTypeMap.changeTrust,
|
|
91
|
-
operationTypeMap.allowTrust,
|
|
92
|
-
operationTypeMap.setTrustLineFlags
|
|
93
|
-
]
|
|
94
|
-
case 'dex':
|
|
95
|
-
return [
|
|
96
|
-
operationTypeMap.manageSellOffer,
|
|
97
|
-
operationTypeMap.manageBuyOffer,
|
|
98
|
-
operationTypeMap.createPassiveSellOffer,
|
|
99
|
-
operationTypeMap.liquidityPoolDeposit,
|
|
100
|
-
operationTypeMap.liquidityPoolWithdraw
|
|
101
|
-
]
|
|
102
|
-
case 'settings':
|
|
103
|
-
return [
|
|
104
|
-
operationTypeMap.createAccount,
|
|
105
|
-
operationTypeMap.setOptions,
|
|
106
|
-
operationTypeMap.changeTrust,
|
|
107
|
-
operationTypeMap.allowTrust,
|
|
108
|
-
operationTypeMap.accountMerge,
|
|
109
|
-
operationTypeMap.inflation,
|
|
110
|
-
operationTypeMap.manageData,
|
|
111
|
-
operationTypeMap.bumpSequence,
|
|
112
|
-
operationTypeMap.beginSponsoringFutureReserves,
|
|
113
|
-
operationTypeMap.endSponsoringFutureReserves,
|
|
114
|
-
operationTypeMap.revokeSponsorship,
|
|
115
|
-
operationTypeMap.setTrustLineFlags
|
|
116
|
-
]
|
|
117
|
-
case 'contracts':
|
|
118
|
-
return [
|
|
119
|
-
operationTypeMap.invokeHostFunction,
|
|
120
|
-
operationTypeMap.bumpFootprintExpiration,
|
|
121
|
-
operationTypeMap.restoreFootprint
|
|
122
|
-
]
|
|
123
|
-
default:
|
|
124
|
-
return [parseInt(filter, 10)]
|
|
125
|
-
}
|
|
126
|
-
}
|
|
1
|
+
const operationTypeMap = {
|
|
2
|
+
createAccount: 0,
|
|
3
|
+
payment: 1,
|
|
4
|
+
pathPaymentStrictReceive: 2,
|
|
5
|
+
pathPaymentStrictSend: 13,
|
|
6
|
+
createPassiveSellOffer: 4,
|
|
7
|
+
manageSellOffer: 3,
|
|
8
|
+
manageBuyOffer: 12,
|
|
9
|
+
setOptions: 5,
|
|
10
|
+
changeTrust: 6,
|
|
11
|
+
allowTrust: 7,
|
|
12
|
+
accountMerge: 8,
|
|
13
|
+
inflation: 9,
|
|
14
|
+
manageData: 10,
|
|
15
|
+
bumpSequence: 11,
|
|
16
|
+
createClaimableBalance: 14,
|
|
17
|
+
claimClaimableBalance: 15,
|
|
18
|
+
beginSponsoringFutureReserves: 16,
|
|
19
|
+
endSponsoringFutureReserves: 17,
|
|
20
|
+
revokeSponsorship: 18,
|
|
21
|
+
clawback: 19,
|
|
22
|
+
clawbackClaimableBalance: 20,
|
|
23
|
+
setTrustLineFlags: 21,
|
|
24
|
+
liquidityPoolDeposit: 22,
|
|
25
|
+
liquidityPoolWithdraw: 23,
|
|
26
|
+
invokeHostFunction: 24,
|
|
27
|
+
bumpFootprintExpiration: 25,
|
|
28
|
+
restoreFootprint: 26
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class TypeFilterMatcher {
|
|
32
|
+
/**
|
|
33
|
+
* @param {string[]} filters
|
|
34
|
+
*/
|
|
35
|
+
constructor(filters) {
|
|
36
|
+
if (!filters?.length)
|
|
37
|
+
return
|
|
38
|
+
this.types = new Set()
|
|
39
|
+
for (const filter of filters) {
|
|
40
|
+
this.processFilter(filter)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @type {Set}
|
|
46
|
+
* @readonly
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
types
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get unique set of type filters
|
|
53
|
+
* @return {boolean}
|
|
54
|
+
*/
|
|
55
|
+
match(operationType) {
|
|
56
|
+
return !this.types || this.types.has(operationTypeMap[operationType])
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {string} filter
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
processFilter(filter) {
|
|
64
|
+
for (const type of this.decodeFilter(filter)) {
|
|
65
|
+
this.types.add(type)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {string} filter
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
decodeFilter(filter) {
|
|
74
|
+
switch (filter) {
|
|
75
|
+
case 'payments':
|
|
76
|
+
return [
|
|
77
|
+
operationTypeMap.createAccount,
|
|
78
|
+
operationTypeMap.accountMerge,
|
|
79
|
+
operationTypeMap.payment,
|
|
80
|
+
operationTypeMap.pathPaymentStrictReceive,
|
|
81
|
+
operationTypeMap.pathPaymentStrictSend,
|
|
82
|
+
operationTypeMap.createClaimableBalance,
|
|
83
|
+
operationTypeMap.claimClaimableBalance,
|
|
84
|
+
operationTypeMap.clawback,
|
|
85
|
+
operationTypeMap.clawbackClaimableBalance,
|
|
86
|
+
operationTypeMap.inflation
|
|
87
|
+
]
|
|
88
|
+
case 'trustlines':
|
|
89
|
+
return [
|
|
90
|
+
operationTypeMap.changeTrust,
|
|
91
|
+
operationTypeMap.allowTrust,
|
|
92
|
+
operationTypeMap.setTrustLineFlags
|
|
93
|
+
]
|
|
94
|
+
case 'dex':
|
|
95
|
+
return [
|
|
96
|
+
operationTypeMap.manageSellOffer,
|
|
97
|
+
operationTypeMap.manageBuyOffer,
|
|
98
|
+
operationTypeMap.createPassiveSellOffer,
|
|
99
|
+
operationTypeMap.liquidityPoolDeposit,
|
|
100
|
+
operationTypeMap.liquidityPoolWithdraw
|
|
101
|
+
]
|
|
102
|
+
case 'settings':
|
|
103
|
+
return [
|
|
104
|
+
operationTypeMap.createAccount,
|
|
105
|
+
operationTypeMap.setOptions,
|
|
106
|
+
operationTypeMap.changeTrust,
|
|
107
|
+
operationTypeMap.allowTrust,
|
|
108
|
+
operationTypeMap.accountMerge,
|
|
109
|
+
operationTypeMap.inflation,
|
|
110
|
+
operationTypeMap.manageData,
|
|
111
|
+
operationTypeMap.bumpSequence,
|
|
112
|
+
operationTypeMap.beginSponsoringFutureReserves,
|
|
113
|
+
operationTypeMap.endSponsoringFutureReserves,
|
|
114
|
+
operationTypeMap.revokeSponsorship,
|
|
115
|
+
operationTypeMap.setTrustLineFlags
|
|
116
|
+
]
|
|
117
|
+
case 'contracts':
|
|
118
|
+
return [
|
|
119
|
+
operationTypeMap.invokeHostFunction,
|
|
120
|
+
operationTypeMap.bumpFootprintExpiration,
|
|
121
|
+
operationTypeMap.restoreFootprint
|
|
122
|
+
]
|
|
123
|
+
default:
|
|
124
|
+
return [parseInt(filter, 10)]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
127
|
}
|
package/tx/tx-list-hooks.js
CHANGED
|
@@ -1,19 +1,33 @@
|
|
|
1
|
-
import {useExplorerPaginatedApi} from '../api/explorer-api-paginated-list-hooks'
|
|
2
|
-
import {useExplorerApi} from '../api/explorer-api-hooks'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import {useExplorerPaginatedApi} from '../api/explorer-api-paginated-list-hooks'
|
|
2
|
+
import {useExplorerApi} from '../api/explorer-api-hooks'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* React hook that fetches paginated transaction history from the Explorer API
|
|
6
|
+
* @param {Object} params
|
|
7
|
+
* @param {Object} params.filters - Query filters (e.g., `{account: [address]}`)
|
|
8
|
+
* @param {'asc'|'desc'} [params.order='desc'] - Sort order
|
|
9
|
+
* @param {number} [params.rows=40] - Number of rows per page
|
|
10
|
+
* @param {boolean} [params.updateLocation=true] - Update browser query string on navigation
|
|
11
|
+
* @return {ExplorerApiListResponse}
|
|
12
|
+
*/
|
|
13
|
+
export function useTxHistory({filters, order = 'desc', rows = 40, updateLocation = true}) {
|
|
14
|
+
return useExplorerPaginatedApi(
|
|
15
|
+
{
|
|
16
|
+
path: 'tx',
|
|
17
|
+
query: filters
|
|
18
|
+
}, {
|
|
19
|
+
defaultSortOrder: order,
|
|
20
|
+
limit: rows,
|
|
21
|
+
updateLocation,
|
|
22
|
+
defaultQueryParams: {order}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* React hook that fetches transaction details by ID or hash
|
|
28
|
+
* @param {string} idOrHash - Transaction ID or hash
|
|
29
|
+
* @return {ExplorerApiResult}
|
|
30
|
+
*/
|
|
31
|
+
export function useTxInfo(idOrHash) {
|
|
32
|
+
return useExplorerApi(`tx/${idOrHash}`)
|
|
19
33
|
}
|
package/tx/tx-operations-list.js
CHANGED
|
@@ -1,116 +1,117 @@
|
|
|
1
|
-
import React, {useCallback, useState} from 'react'
|
|
2
|
-
import {Spoiler} from '../interaction/spoiler'
|
|
3
|
-
import {OpEffectsView} from '../effect/op-effects-view'
|
|
4
|
-
import {OpAccountingChanges, TxFeeAccountingChanges} from './op-accounting-changes'
|
|
5
|
-
import TxFeeEffect from './tx-fee-effect'
|
|
6
|
-
import {OpDescriptionView} from './op-description-view'
|
|
7
|
-
import {OpIcon} from './op-icon'
|
|
8
|
-
import './op-description.scss'
|
|
9
|
-
|
|
10
|
-
/*
|
|
11
|
-
Every operation can be in one of the following states (detected automatically):
|
|
12
|
-
- Ephemeral
|
|
13
|
-
- Pending (not processed by StellarCore yet)
|
|
14
|
-
- Rejected (rejected by Horizon or StellarCore during execution)
|
|
15
|
-
- Applied
|
|
16
|
-
- Processed (applied to the ledger and resulted in some on-chain state changes)
|
|
17
|
-
- Processed without effects (applied to the ledger but yielded no changes in the ledger state)
|
|
18
|
-
- Failed during the execution
|
|
19
|
-
|
|
20
|
-
Display context
|
|
21
|
-
- Transaction context
|
|
22
|
-
- All operations displayed
|
|
23
|
-
- Source account always visible
|
|
24
|
-
- No fee charges
|
|
25
|
-
- Effects displayed
|
|
26
|
-
- Unfiltered view context
|
|
27
|
-
- All operations displayed
|
|
28
|
-
- Source account always visible
|
|
29
|
-
- No fee charges
|
|
30
|
-
- All effects displayed
|
|
31
|
-
- Filtered view context
|
|
32
|
-
- Only operations related to the filter context (account/asset/order)
|
|
33
|
-
- Source account always visible
|
|
34
|
-
- Fee charges ony for account context
|
|
35
|
-
- Effects related to the filter context
|
|
36
|
-
- Account history view context
|
|
37
|
-
- Only operations DIRECTLY related to the current account (skip third-party operations for claimable balances, sponsorship, etc)
|
|
38
|
-
- Source account displayed only when operation (or transaction) source account not matches current account
|
|
39
|
-
- Fee charge effects displayed only if charged from the current account
|
|
40
|
-
- Effects related to the current account
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
const TxChargedFee = React.memo(function TxChargedFee({parsedTx, compact}) {
|
|
44
|
-
if (parsedTx.isEphemeral || !parsedTx.context?.account)
|
|
45
|
-
return null
|
|
46
|
-
const fee = parsedTx.effects.find(e => e.type === 'feeCharged')
|
|
47
|
-
if (!fee || !parsedTx.context.account.includes(fee.source))
|
|
48
|
-
return null
|
|
49
|
-
return <div className="op-container">
|
|
50
|
-
<div className="op-layout">
|
|
51
|
-
<OpIcon op="feeCharge" failed={!parsedTx.successful}/>
|
|
52
|
-
<TxFeeEffect feeEffect={fee} compact={compact}/>
|
|
53
|
-
{!!compact && !parsedTx.isEphemeral && <TxFeeAccountingChanges amount={fee.charged}/>}
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
*
|
|
60
|
-
* @param {
|
|
61
|
-
* @param {
|
|
62
|
-
* @param {
|
|
63
|
-
* @param {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const [
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
import React, {useCallback, useState} from 'react'
|
|
2
|
+
import {Spoiler} from '../interaction/spoiler'
|
|
3
|
+
import {OpEffectsView} from '../effect/op-effects-view'
|
|
4
|
+
import {OpAccountingChanges, TxFeeAccountingChanges} from './op-accounting-changes'
|
|
5
|
+
import TxFeeEffect from './tx-fee-effect'
|
|
6
|
+
import {OpDescriptionView} from './op-description-view'
|
|
7
|
+
import {OpIcon} from './op-icon'
|
|
8
|
+
import './op-description.scss'
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
Every operation can be in one of the following states (detected automatically):
|
|
12
|
+
- Ephemeral
|
|
13
|
+
- Pending (not processed by StellarCore yet)
|
|
14
|
+
- Rejected (rejected by Horizon or StellarCore during execution)
|
|
15
|
+
- Applied
|
|
16
|
+
- Processed (applied to the ledger and resulted in some on-chain state changes)
|
|
17
|
+
- Processed without effects (applied to the ledger but yielded no changes in the ledger state)
|
|
18
|
+
- Failed during the execution
|
|
19
|
+
|
|
20
|
+
Display context
|
|
21
|
+
- Transaction context
|
|
22
|
+
- All operations displayed
|
|
23
|
+
- Source account always visible
|
|
24
|
+
- No fee charges
|
|
25
|
+
- Effects displayed
|
|
26
|
+
- Unfiltered view context
|
|
27
|
+
- All operations displayed
|
|
28
|
+
- Source account always visible
|
|
29
|
+
- No fee charges
|
|
30
|
+
- All effects displayed
|
|
31
|
+
- Filtered view context
|
|
32
|
+
- Only operations related to the filter context (account/asset/order)
|
|
33
|
+
- Source account always visible
|
|
34
|
+
- Fee charges ony for account context
|
|
35
|
+
- Effects related to the filter context
|
|
36
|
+
- Account history view context
|
|
37
|
+
- Only operations DIRECTLY related to the current account (skip third-party operations for claimable balances, sponsorship, etc)
|
|
38
|
+
- Source account displayed only when operation (or transaction) source account not matches current account
|
|
39
|
+
- Fee charge effects displayed only if charged from the current account
|
|
40
|
+
- Effects related to the current account
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
const TxChargedFee = React.memo(function TxChargedFee({parsedTx, compact}) {
|
|
44
|
+
if (parsedTx.isEphemeral || !parsedTx.context?.account)
|
|
45
|
+
return null
|
|
46
|
+
const fee = parsedTx.effects.find(e => e.type === 'feeCharged')
|
|
47
|
+
if (!fee || !parsedTx.context.account.includes(fee.source))
|
|
48
|
+
return null
|
|
49
|
+
return <div className="op-container">
|
|
50
|
+
<div className="op-layout">
|
|
51
|
+
<OpIcon op="feeCharge" failed={!parsedTx.successful}/>
|
|
52
|
+
<TxFeeEffect feeEffect={fee} compact={compact}/>
|
|
53
|
+
{!!compact && !parsedTx.isEphemeral && <TxFeeAccountingChanges amount={fee.charged}/>}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Renders a list of transaction operations
|
|
60
|
+
* @param {ParsedTxDetails} parsedTx - Transaction descriptor
|
|
61
|
+
* @param {function} [filter] - Filter matcher function
|
|
62
|
+
* @param {boolean} [showFees] - Whether to display transaction fees
|
|
63
|
+
* @param {boolean} [showEffects] - Whether to show operation effects
|
|
64
|
+
* @param {boolean} [compact] - Compact view (without fee charges and accounting changes effects)
|
|
65
|
+
*/
|
|
66
|
+
export const TxOperationsList = React.memo(function TxOperationsList({
|
|
67
|
+
parsedTx,
|
|
68
|
+
filter = null,
|
|
69
|
+
showFees = true,
|
|
70
|
+
compact = false,
|
|
71
|
+
showEffects
|
|
72
|
+
}) {
|
|
73
|
+
const [effectsExpanded, setEffectsExpanded] = useState(false)
|
|
74
|
+
const [opsExpanded, setOpsExpanded] = useState(false)
|
|
75
|
+
const toggleEffects = useCallback(e => setEffectsExpanded(e.expanded), [])
|
|
76
|
+
const toggleAdditionalOps = useCallback(e => setOpsExpanded(e.expanded), [])
|
|
77
|
+
let {operations, successful} = parsedTx
|
|
78
|
+
let opdiff = 0
|
|
79
|
+
if (!opsExpanded) {
|
|
80
|
+
//filter operations if filtered output is requested
|
|
81
|
+
if (filter) {
|
|
82
|
+
const visibleOps = operations.filter(filter)
|
|
83
|
+
if (visibleOps.length) {
|
|
84
|
+
operations = visibleOps
|
|
85
|
+
opdiff = parsedTx.operations.length - operations.length
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//hide some operations in large transactions to prevent interface hanging
|
|
89
|
+
if (operations.length > 5) {
|
|
90
|
+
operations = operations.slice(0, 5)
|
|
91
|
+
opdiff = parsedTx.operations.length - operations.length
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return <div>
|
|
96
|
+
{!compact && showEffects !== false &&
|
|
97
|
+
<div className="tx-effects-toggle">
|
|
98
|
+
<Spoiler micro active expanded={effectsExpanded} showLess="Hide operation details" showMore="Show operation details"
|
|
99
|
+
onChange={toggleEffects} style={{margin: '0.2em'}}/>
|
|
100
|
+
</div>}
|
|
101
|
+
<div className="condensed">
|
|
102
|
+
{operations.map((op, i) => <div className="op-container" key={op.txHash + op.order + op.isEphemeral}>
|
|
103
|
+
<div className="op-layout">
|
|
104
|
+
<OpIcon op={op} failed={!successful}/>
|
|
105
|
+
<div>
|
|
106
|
+
<OpDescriptionView key={parsedTx.txHash + op.order} op={op} compact={compact}/>
|
|
107
|
+
</div>
|
|
108
|
+
{!!compact && !op.isEphemeral && <OpAccountingChanges op={op}/>}
|
|
109
|
+
</div>
|
|
110
|
+
{effectsExpanded && <OpEffectsView operation={op}/>}
|
|
111
|
+
</div>)}
|
|
112
|
+
{showFees && <TxChargedFee {...{parsedTx, compact}}/>}
|
|
113
|
+
</div>
|
|
114
|
+
{(opsExpanded || opdiff > 0) && <Spoiler className="text-tiny" expanded={opsExpanded} onChange={toggleAdditionalOps}
|
|
115
|
+
showMore={`${opdiff} more operation${opdiff > 1 ? 's' : ''} in this transaction`} showLess="Hide additional operations"/>}
|
|
116
|
+
</div>
|
|
117
|
+
})
|