@stellar-expert/ui-framework 1.13.0 → 1.13.2
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/contract/invocation-info-view.js +3 -3
- package/controls/info-tooltip.js +1 -1
- package/controls/tooltip.js +8 -5
- package/controls/tooltip.scss +9 -10
- package/date/date-selector.js +25 -14
- package/effect/effect-description.js +6 -2
- package/effect/op-effects-view.js +3 -2
- package/effect/op-effects.scss +1 -1
- package/package.json +2 -2
- package/tx/parser/tx-details-parser.js +1 -1
|
@@ -22,9 +22,9 @@ export default function InvocationInfoView({contract, func, args, result, sac})
|
|
|
22
22
|
<code>{func}({args.map((arg, i) => <ScValStruct key={i} separate={args.length - i}>
|
|
23
23
|
<ScVal value={arg} nested/>
|
|
24
24
|
</ScValStruct>)})<InvocationResult result={result}/></code>
|
|
25
|
-
<Tooltip trigger={<i className="trigger icon-info"/>} desiredPlace="top" activation="click" maxWidth="
|
|
25
|
+
<Tooltip trigger={<i className="trigger icon-info"/>} desiredPlace="top" activation="click" maxWidth="Min(60em, 40vw)">
|
|
26
26
|
<ExtendedInvocationInfoView {...{contract, func, args, result, sac}}/>
|
|
27
|
-
</Tooltip
|
|
27
|
+
</Tooltip>
|
|
28
28
|
</>
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -68,7 +68,7 @@ const ExtendedInvocationInfoView = React.memo(function ({contract, func, args, r
|
|
|
68
68
|
<div className="text-small space">
|
|
69
69
|
{fd.doc ?
|
|
70
70
|
<>{fd.doc.split('\n').filter(v => !!v).map((v, i) => <div key={i}>{v}</div>)}</> :
|
|
71
|
-
<span className="dimmed">
|
|
71
|
+
<span className="dimmed text-tiny">No function documentation is available in the contract WASM</span>}
|
|
72
72
|
</div>
|
|
73
73
|
</div>
|
|
74
74
|
})
|
package/controls/info-tooltip.js
CHANGED
|
@@ -5,7 +5,7 @@ import {Tooltip} from './tooltip'
|
|
|
5
5
|
import './info-tooltip.scss'
|
|
6
6
|
|
|
7
7
|
export const InfoTooltip = React.memo(function InfoTooltip({children, link, icon = 'icon-help', ...otherProps}) {
|
|
8
|
-
return <Tooltip trigger={<i className={cn('trigger icon info-tooltip small', icon)} {...otherProps}/>}>
|
|
8
|
+
return <Tooltip trigger={<i className={cn('trigger icon info-tooltip small', icon)} {...otherProps}/>} maxWidth="30em">
|
|
9
9
|
{children}
|
|
10
10
|
{!!link && <a href={link} className="info-tooltip-link" target="_blank">Read more…</a>}
|
|
11
11
|
</Tooltip>
|
package/controls/tooltip.js
CHANGED
|
@@ -166,7 +166,7 @@ export const Tooltip = React.memo(function Tooltip({
|
|
|
166
166
|
offset = {},
|
|
167
167
|
activation = 'hover',
|
|
168
168
|
children,
|
|
169
|
-
maxWidth
|
|
169
|
+
maxWidth,
|
|
170
170
|
...op
|
|
171
171
|
}) {
|
|
172
172
|
const [visible, setVisible] = useState(false)
|
|
@@ -187,7 +187,7 @@ export const Tooltip = React.memo(function Tooltip({
|
|
|
187
187
|
setVisible(true)
|
|
188
188
|
setPosition(position)
|
|
189
189
|
setPlace(place)
|
|
190
|
-
},
|
|
190
|
+
}, 400)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
function onMouseLeave(e) {
|
|
@@ -206,13 +206,16 @@ export const Tooltip = React.memo(function Tooltip({
|
|
|
206
206
|
} else {
|
|
207
207
|
triggerProps.onClick = activate
|
|
208
208
|
}
|
|
209
|
-
const
|
|
210
|
-
maxWidth,
|
|
209
|
+
const containerStyle = {
|
|
211
210
|
left: position.left + 'px',
|
|
212
211
|
top: position.top + 'px'
|
|
213
212
|
}
|
|
213
|
+
if (maxWidth) {
|
|
214
|
+
containerStyle.width = '100vw'
|
|
215
|
+
containerStyle.maxWidth = maxWidth
|
|
216
|
+
}
|
|
214
217
|
|
|
215
|
-
return React.cloneElement(trigger, triggerProps, <div className="tooltip-wrapper" style={
|
|
218
|
+
return React.cloneElement(trigger, triggerProps, <div className="tooltip-wrapper" style={containerStyle}>
|
|
216
219
|
<div ref={content} className={cn('tooltip', place, {visible})}>
|
|
217
220
|
<div className="tooltip-content">{rendered ? children : null}</div>
|
|
218
221
|
</div>
|
package/controls/tooltip.scss
CHANGED
|
@@ -4,7 +4,7 @@ $tooltip-notch-shadow-color: var(--color-border-shadow);
|
|
|
4
4
|
|
|
5
5
|
.tooltip-wrapper {
|
|
6
6
|
width: 40rem;
|
|
7
|
-
max-width: Min(40rem,
|
|
7
|
+
max-width: Min(40rem, 60vw);
|
|
8
8
|
position: absolute;
|
|
9
9
|
visibility: hidden;
|
|
10
10
|
opacity: 0;
|
|
@@ -17,7 +17,6 @@ $tooltip-notch-shadow-color: var(--color-border-shadow);
|
|
|
17
17
|
font-size: 0.9*$font-size-base;
|
|
18
18
|
font-style: normal;
|
|
19
19
|
line-height: 1.3;
|
|
20
|
-
max-width: Min(40rem, 80vw);
|
|
21
20
|
background: var(--color-bg);
|
|
22
21
|
border-color: var(--color-contrast-border);
|
|
23
22
|
border-radius: $border-radius-input;
|
|
@@ -76,11 +75,11 @@ $tooltip-notch-shadow-color: var(--color-border-shadow);
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
.trigger {
|
|
79
|
-
|
|
78
|
+
position: absolute;
|
|
80
79
|
font-size: 1.2rem;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
margin-top: -.3rem;
|
|
81
|
+
margin-left: .1rem;
|
|
82
|
+
margin-right: .1rem;
|
|
84
83
|
color: var(--color-primary);
|
|
85
84
|
|
|
86
85
|
&:before {
|
|
@@ -92,10 +91,10 @@ $tooltip-notch-shadow-color: var(--color-border-shadow);
|
|
|
92
91
|
position: absolute;
|
|
93
92
|
opacity: 0.01;
|
|
94
93
|
display: block;
|
|
95
|
-
width:
|
|
96
|
-
height:
|
|
97
|
-
left: -
|
|
98
|
-
top: -
|
|
94
|
+
width: 2em;
|
|
95
|
+
height: 2em;
|
|
96
|
+
left: -0.4em;
|
|
97
|
+
top: -0.2em;
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
&:hover {
|
package/date/date-selector.js
CHANGED
|
@@ -2,19 +2,12 @@ import React, {useCallback, useEffect, useState} from 'react'
|
|
|
2
2
|
import {debounce} from 'throttle-debounce'
|
|
3
3
|
import {normalizeDate, toUnixTimestamp} from '@stellar-expert/formatter'
|
|
4
4
|
|
|
5
|
-
export function trimIsoDateSeconds(date) {
|
|
6
|
-
if (typeof date === 'number') {
|
|
7
|
-
date = new Date(date)
|
|
8
|
-
}
|
|
9
|
-
return date.toISOString().replace(/:\d{2}\.\d*Z/, '')
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const minSelectableValue = trimIsoDateSeconds(new Date('2015-09-30T16:46:00Z'))
|
|
13
|
-
|
|
14
5
|
/**
|
|
15
|
-
* @param {String} value
|
|
16
|
-
* @param {
|
|
17
|
-
* @
|
|
6
|
+
* @param {String} value - Current input value
|
|
7
|
+
* @param {DateSelector~OnChange} onChange - Onchange event handler
|
|
8
|
+
* @param {String} [min] - Minimum allowed date
|
|
9
|
+
* @param {String} [max] - Maximum allowed date
|
|
10
|
+
* @param {*} [ref]
|
|
18
11
|
*/
|
|
19
12
|
export function DateSelector({value, onChange, min, max, ref, ...otherProps}) {
|
|
20
13
|
const [date, setDate] = useState(value ? trimIsoDateSeconds(normalizeDate(value)) : '')
|
|
@@ -30,7 +23,7 @@ export function DateSelector({value, onChange, min, max, ref, ...otherProps}) {
|
|
|
30
23
|
if (value !== newDate) {
|
|
31
24
|
setDate(newDate)
|
|
32
25
|
if (onChange) {
|
|
33
|
-
onChange(toUnixTimestamp(normalizeDate(newDate)))
|
|
26
|
+
onChange(newDate ? toUnixTimestamp(normalizeDate(newDate)) : null)
|
|
34
27
|
}
|
|
35
28
|
}
|
|
36
29
|
}), [onChange, value])
|
|
@@ -41,4 +34,22 @@ export function DateSelector({value, onChange, min, max, ref, ...otherProps}) {
|
|
|
41
34
|
return <input type="datetime-local" value={date} className="date-selector condensed" step={60} ref={ref}
|
|
42
35
|
min={min || minSelectableValue} max={max} onChange={e => selectDate(e.target.value)}
|
|
43
36
|
style={{width: '11em', overflow: 'hidden'}} {...otherProps}/>
|
|
44
|
-
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {Date|Number} date
|
|
41
|
+
* @return {String}
|
|
42
|
+
*/
|
|
43
|
+
export function trimIsoDateSeconds(date) {
|
|
44
|
+
if (typeof date === 'number') {
|
|
45
|
+
date = new Date(date)
|
|
46
|
+
}
|
|
47
|
+
return date.toISOString().replace(/:\d{2}\.\d*Z/, '')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const minSelectableValue = trimIsoDateSeconds(new Date('2015-09-30T16:46:00Z'))
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @callback DateSelector~OnChange
|
|
54
|
+
* @param {number|null} value - Selected value represented as a Unix timestamp or null for invalid date value
|
|
55
|
+
*/
|
|
@@ -232,8 +232,12 @@ export function EffectDescription({effect, operation}) {
|
|
|
232
232
|
case 'contractDataRemoved':
|
|
233
233
|
return <>Contract <AccountAddress account={effect.owner}/> removed {effect.durability} data <ScVal value={effect.key}/></>
|
|
234
234
|
case 'contractError':
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
let errCode = effect.code
|
|
236
|
+
if (errCode?.name) {
|
|
237
|
+
errCode = errCode.name
|
|
238
|
+
}
|
|
239
|
+
return <>Execution error {errCode ? <><code>{errCode}</code> </> : null}in <AccountAddress account={effect.contract}/>{': '}
|
|
240
|
+
<code>{JSON.stringify(effect.details)}</code> </>
|
|
237
241
|
case 'feeCharged':
|
|
238
242
|
return <><Amount asset="XLM" amount={effect.charged} adjust/> fee charged from <AccountAddress account={effect.source}/> (
|
|
239
243
|
bid <Amount asset="XLM" amount={effect.bid} adjust/>)</>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import cn from 'classnames'
|
|
2
3
|
import {EffectDescription} from './effect-description'
|
|
3
4
|
import SorobanTxMetricsView from './soroban-tx-metrics-view'
|
|
4
5
|
import './op-effects.scss'
|
|
@@ -14,7 +15,7 @@ export function OpEffectsView({operation}) {
|
|
|
14
15
|
if (e.type === 'contractMetrics')
|
|
15
16
|
return null
|
|
16
17
|
return <div key={i}>
|
|
17
|
-
<i className={e.type === 'contractError' ? 'icon-warning' : 'icon-puzzle'}
|
|
18
|
+
<i className={cn('effect-icon', e.type === 'contractError' ? 'icon-warning' : 'icon-puzzle')}/> 
|
|
18
19
|
<EffectDescription effect={e} operation={operation}/>
|
|
19
20
|
</div>
|
|
20
21
|
})}
|
|
@@ -35,7 +36,7 @@ function sortContractEffects(effects) {
|
|
|
35
36
|
const bInvocation = b.type === 'contractInvoked'
|
|
36
37
|
if (aInvocation && bInvocation)
|
|
37
38
|
return 0
|
|
38
|
-
if (!aInvocation && !bInvocation){
|
|
39
|
+
if (!aInvocation && !bInvocation) {
|
|
39
40
|
const aData = a.type.startsWith('contractData')
|
|
40
41
|
const bData = b.type.startsWith('contractData')
|
|
41
42
|
if (aData === bData)
|
package/effect/op-effects.scss
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stellar-expert/ui-framework",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.2",
|
|
4
4
|
"description": "StellarExpert shared UI components library",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@stellar-expert/contract-wasm-interface-parser": "^3.1.0",
|
|
23
23
|
"@stellar-expert/formatter": "^2.3.0",
|
|
24
24
|
"@stellar-expert/navigation": "github:stellar-expert/navigation#v1.0.2",
|
|
25
|
-
"@stellar-expert/tx-meta-effects-parser": "5.
|
|
25
|
+
"@stellar-expert/tx-meta-effects-parser": "5.7.0",
|
|
26
26
|
"classnames": ">=2",
|
|
27
27
|
"prop-types": ">=15",
|
|
28
28
|
"qrcode.react": "^3.1.0",
|
|
@@ -43,7 +43,7 @@ import TxMatcher from './tx-matcher'
|
|
|
43
43
|
* @return {ParsedTxDetails}
|
|
44
44
|
*/
|
|
45
45
|
export function parseTxDetails({network, txEnvelope, result, meta, id, context, createdAt, skipUnrelated, protocol}) {
|
|
46
|
-
const parsedTx = parseTxOperationsMeta({network, tx: txEnvelope, meta, result, protocol, processSystemEvents: true, mapSac: true})
|
|
46
|
+
const parsedTx = parseTxOperationsMeta({network, tx: txEnvelope, meta, result, protocol, processSystemEvents: true, processFailedOpEffects: true, mapSac: true})
|
|
47
47
|
const {tx, effects, operations, isEphemeral, failed} = parsedTx
|
|
48
48
|
const txHash = tx.hash().toString('hex')
|
|
49
49
|
const txMatcher = new TxMatcher(context, skipUnrelated)
|