@stellar-expert/ui-framework 1.16.7 → 1.17.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.
Files changed (92) hide show
  1. package/CLAUDE.md +35 -0
  2. package/README.md +1125 -3
  3. package/account/account-address.js +127 -127
  4. package/account/available-balance.js +22 -22
  5. package/account/identicon.js +90 -90
  6. package/account/signer-key.js +65 -64
  7. package/api/explorer-api-hooks.js +209 -202
  8. package/api/explorer-api-paginated-list-hooks.js +441 -440
  9. package/api/explorer-batch-info-loader.js +111 -85
  10. package/api/explorer-tx-api.js +28 -28
  11. package/api/ledger-stream.js +15 -0
  12. package/asset/amount.js +56 -56
  13. package/asset/asset-icon.js +41 -41
  14. package/asset/asset-issuer.js +21 -21
  15. package/asset/asset-link.js +107 -107
  16. package/asset/asset-list-hooks.js +59 -59
  17. package/asset/asset-meta-hooks.js +88 -88
  18. package/asset/asset-selector.js +72 -71
  19. package/basic-styles/base.scss +50 -50
  20. package/basic-styles/grid.scss +1 -1
  21. package/basic-styles/table.scss +1 -1
  22. package/claimable-balance/claimable-balance-claimants.js +5 -0
  23. package/contract/contract-api.js +15 -0
  24. package/contract/invocation-info-view.js +10 -2
  25. package/contract/sc-val.js +24 -0
  26. package/controls/button-group.js +25 -19
  27. package/controls/button-group.scss +46 -46
  28. package/controls/button.js +93 -78
  29. package/controls/button.scss +173 -173
  30. package/controls/code-block.js +42 -34
  31. package/controls/code-block.scss +71 -71
  32. package/controls/dropdown.js +318 -287
  33. package/controls/dropdown.scss +159 -159
  34. package/controls/external-link.js +10 -4
  35. package/controls/info-tooltip.js +23 -16
  36. package/controls/slider.js +29 -19
  37. package/controls/tabs.js +94 -94
  38. package/controls/tabs.scss +70 -70
  39. package/controls/tooltip.js +244 -240
  40. package/controls/tooltip.scss +116 -116
  41. package/controls/update-highlighter.js +32 -27
  42. package/controls/update-highlighter.scss +7 -7
  43. package/date/date-selector.js +56 -54
  44. package/date/elapsed-time.js +28 -21
  45. package/dex/price-dynamic.js +53 -44
  46. package/dex/price-dynamic.scss +33 -33
  47. package/directory/directory-hooks.js +109 -97
  48. package/effect/effect-description.js +5 -3
  49. package/errors/error-boundary.js +110 -97
  50. package/horizon/horizon-account-helpers.js +104 -104
  51. package/horizon/horizon-ledger-helpers.js +35 -35
  52. package/horizon/horizon-trades-helper.js +88 -88
  53. package/horizon/horizon-transaction-helpers.js +36 -36
  54. package/index.d.ts +1241 -0
  55. package/interaction/accordion.js +43 -35
  56. package/interaction/autofocus.js +13 -9
  57. package/interaction/block-select.js +64 -53
  58. package/interaction/block-select.scss +21 -21
  59. package/interaction/copy-to-clipboard.js +25 -18
  60. package/interaction/inline-progress.js +20 -15
  61. package/interaction/qr-code.js +34 -34
  62. package/interaction/responsive.js +20 -20
  63. package/interaction/spoiler.js +52 -39
  64. package/interaction/spoiler.scss +6 -6
  65. package/interaction/theme-selector.js +13 -10
  66. package/ledger/ledger-entry-href-formatter.js +4 -3
  67. package/ledger/ledger-entry-link.js +93 -58
  68. package/ledger/ledger-info-parser.js +28 -0
  69. package/meta/page-meta-tags.js +243 -238
  70. package/module/dynamic-module.js +47 -47
  71. package/package.json +3 -2
  72. package/state/on-screen-hooks.js +22 -22
  73. package/state/page-visibility-helpers.js +29 -16
  74. package/state/page-visibility-hooks.js +13 -11
  75. package/state/screen-orientation-hooks.js +19 -15
  76. package/state/state-hooks.js +76 -76
  77. package/state/stellar-network-hooks.js +56 -44
  78. package/state/theme.js +29 -28
  79. package/stellar/key-type.js +92 -91
  80. package/stellar/ledger-generic-id.js +39 -39
  81. package/stellar/signature-hint-utils.js +65 -65
  82. package/toast/toast-notifications-block.js +59 -59
  83. package/toast/toast-notifications.scss +1 -1
  84. package/tx/op-description-view.js +84 -81
  85. package/tx/op-icon.js +98 -98
  86. package/tx/parser/op-balance-changes.js +66 -66
  87. package/tx/parser/op-descriptor.js +51 -48
  88. package/tx/parser/tx-details-parser.js +81 -81
  89. package/tx/parser/tx-matcher.js +371 -371
  90. package/tx/parser/type-filter-matcher.js +126 -126
  91. package/tx/tx-list-hooks.js +32 -18
  92. 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 {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
- }
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
  }
@@ -1,19 +1,33 @@
1
- import {useExplorerPaginatedApi} from '../api/explorer-api-paginated-list-hooks'
2
- import {useExplorerApi} from '../api/explorer-api-hooks'
3
-
4
- export function useTxHistory({filters, order = 'desc', rows = 40, updateLocation = true}) {
5
- return useExplorerPaginatedApi(
6
- {
7
- path: 'tx',
8
- query: filters
9
- }, {
10
- defaultSortOrder: order,
11
- limit: rows,
12
- updateLocation,
13
- defaultQueryParams: {order}
14
- })
15
- }
16
-
17
- export function useTxInfo(idOrHash) {
18
- return useExplorerApi(`tx/${idOrHash}`)
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
  }
@@ -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
- * @param {ParsedTxDetails} parsedTx - Transaction descriptor
60
- * @param {Function} [filter] - Filter matcher function
61
- * @param {Boolean} [showFees] - Whether to display transaction fees
62
- * @param {Boolean} [showEffects] - Whether to show operation effects
63
- * @param {Boolean} [compact] - Compact view (without fee charges and accounting changes effects)
64
- */
65
- export const TxOperationsList = React.memo(function TxOperationsList({
66
- parsedTx,
67
- filter = null,
68
- showFees = true,
69
- compact = false,
70
- showEffects
71
- }) {
72
- const [effectsExpanded, setEffectsExpanded] = useState(false)
73
- const [opsExpanded, setOpsExpanded] = useState(false)
74
- const toggleEffects = useCallback(e => setEffectsExpanded(e.expanded), [])
75
- const toggleAdditionalOps = useCallback(e => setOpsExpanded(e.expanded), [])
76
- let {operations, successful} = parsedTx
77
- let opdiff = 0
78
- if (!opsExpanded) {
79
- //filter operations if filtered output is requested
80
- if (filter) {
81
- const visibleOps = operations.filter(filter)
82
- if (visibleOps.length) {
83
- operations = visibleOps
84
- opdiff = parsedTx.operations.length - operations.length
85
- }
86
- }
87
- //hide some operations in large transactions to prevent interface hanging
88
- if (operations.length > 5) {
89
- operations = operations.slice(0, 5)
90
- opdiff = parsedTx.operations.length - operations.length
91
- }
92
- }
93
-
94
- return <div>
95
- {!compact && showEffects !== false &&
96
- <div className="tx-effects-toggle">
97
- <Spoiler micro active expanded={effectsExpanded} showLess="Hide operation details" showMore="Show operation details"
98
- onChange={toggleEffects} style={{margin: '0.2em'}}/>
99
- </div>}
100
- <div className="condensed">
101
- {operations.map((op, i) => <div className="op-container" key={op.txHash + op.order + op.isEphemeral}>
102
- <div className="op-layout">
103
- <OpIcon op={op} failed={!successful}/>
104
- <div>
105
- <OpDescriptionView key={parsedTx.txHash + op.order} op={op} compact={compact}/>
106
- </div>
107
- {!!compact && !op.isEphemeral && <OpAccountingChanges op={op}/>}
108
- </div>
109
- {effectsExpanded && <OpEffectsView operation={op}/>}
110
- </div>)}
111
- {showFees && <TxChargedFee {...{parsedTx, compact}}/>}
112
- </div>
113
- {(opsExpanded || opdiff > 0) && <Spoiler className="text-tiny" expanded={opsExpanded} onChange={toggleAdditionalOps}
114
- showMore={`${opdiff} more operation${opdiff > 1 ? 's' : ''} in this transaction`} showLess="Hide additional operations"/>}
115
- </div>
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
+ })