Skip to content

Commit 7b21c84

Browse files
committed
Merge branch 'staging' into entry-page
2 parents c2abd3f + 058f219 commit 7b21c84

File tree

14 files changed

+588
-508
lines changed

14 files changed

+588
-508
lines changed

.github/dependabot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ updates:
33
- package-ecosystem: npm
44
directory: '/'
55
schedule:
6-
interval: monthly
6+
interval: quarterly
77
time: '15:00'
8-
open-pull-requests-limit: 10
8+
open-pull-requests-limit: 30

src/containers/Token/MPT/Header/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
shortenDomain,
99
shortenMPTID,
1010
stripHttpProtocol,
11+
convertToHttpURL,
1112
} from '../../../shared/utils'
1213
import { CopyableText } from '../../../shared/components/CopyableText'
1314
import DomainLink from '../../../shared/components/DomainLink'
@@ -102,6 +103,9 @@ export const Header = (props: Props) => {
102103
// Only show MPT issuance ID if ticker exists (since we show ticker in header, need to show ID somewhere)
103104
const showMPTIssuanceId = !!ticker
104105

106+
// Convert logo URL to HTTP/HTTPS format (handles IPFS URLs)
107+
const RenderedLogoUrl = logoUrl ? convertToHttpURL(logoUrl) : undefined
108+
105109
// Get all URIs for dropdown, filtering out items without uri
106110
const allUris = (uris || []).filter((u) => u.uri)
107111

@@ -137,11 +141,11 @@ export const Header = (props: Props) => {
137141
</div>
138142
<div className="section box-header">
139143
<div className="token-info-group">
140-
{logoUrl ? (
144+
{RenderedLogoUrl ? (
141145
<img
142146
className="token-logo"
143147
alt={`${ticker || mptIssuanceId} logo`}
144-
src={logoUrl}
148+
src={RenderedLogoUrl}
145149
/>
146150
) : (
147151
<DefaultTokenIcon className="token-logo no-logo" />

src/containers/Token/MPT/test/Header/Header.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ describe('MPT Header component', () => {
115115
wrapper.unmount()
116116
})
117117

118+
it('displays logo URL without protocol by prefixing https', () => {
119+
const dataWithNoProtocolUrl = {
120+
...mockMPTData,
121+
parsedMPTMetadata: {
122+
...mockMPTData.parsedMPTMetadata,
123+
icon: 'example.com/logo.png',
124+
},
125+
}
126+
const wrapper = createWrapper({ data: dataWithNoProtocolUrl })
127+
const logo = wrapper.find('img.token-logo')
128+
expect(logo.length).toBe(1)
129+
expect(logo.prop('src')).toBe('https://example.com/logo.png')
130+
wrapper.unmount()
131+
})
132+
118133
it('displays default logo when no icon', () => {
119134
const wrapper = createWrapper({ data: mockMPTDataNoMetadata })
120135
expect(wrapper.find('.token-logo.no-logo').length).toBeGreaterThanOrEqual(1)

src/containers/shared/test/utils.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
shortenNFTTokenID,
1414
shortenMPTID,
1515
stripHttpProtocol,
16+
convertToHttpURL,
1617
} from '../utils'
1718

1819
describe('utils', () => {
@@ -271,4 +272,38 @@ describe('Shorten utils', () => {
271272
expect(shortenMPTID(shortMPTID)).toBe(shortMPTID)
272273
})
273274
})
275+
276+
describe('convertToHttpUrl', () => {
277+
it('converts IPFS URLs to HTTP URLs', () => {
278+
expect(
279+
convertToHttpURL(
280+
'ipfs://QmXhvvWs3HaFkJvDuYvanj2pv31yFQGJewfEhfme1Sv47Y',
281+
),
282+
).toBe(
283+
'https://ipfs.io/ipfs/QmXhvvWs3HaFkJvDuYvanj2pv31yFQGJewfEhfme1Sv47Y',
284+
)
285+
})
286+
287+
it('preserves https:// URLs as-is', () => {
288+
expect(convertToHttpURL('https://example.com/logo.png')).toBe(
289+
'https://example.com/logo.png',
290+
)
291+
})
292+
293+
it('adds https:// to plain domain URLs', () => {
294+
expect(convertToHttpURL('logo.svgcdn.com/logos/openai-icon.png')).toBe(
295+
'https://logo.svgcdn.com/logos/openai-icon.png',
296+
)
297+
})
298+
299+
it('handles empty strings', () => {
300+
expect(convertToHttpURL('')).toBe('')
301+
})
302+
303+
it('handles other protocols', () => {
304+
expect(convertToHttpURL('ftp://example.com/file.txt')).toBe(
305+
'ftp://example.com/file.txt',
306+
)
307+
})
308+
})
274309
})

src/containers/shared/utils.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,30 @@ export const shortenMPTID = (
557557

558558
export const shortenTxHash = (txHash = '') =>
559559
txHash.length > 12 ? `${txHash.slice(0, 6)}...${txHash.slice(-6)}` : txHash
560+
561+
/**
562+
* Converts URLs to HTTP/HTTPS format, handling IPFS URLs and plain domains
563+
* @param {string} url - The URL to convert (can be ipfs://, https://, http://, or plain domain)
564+
* @returns {string} The converted HTTP/HTTPS URL
565+
*/
566+
export const convertToHttpURL = (url) => {
567+
if (!url) {
568+
return url
569+
}
570+
571+
// Handle IPFS URLs - convert to HTTP
572+
if (url.startsWith('ipfs://')) {
573+
return url.replace('ipfs://', 'https://ipfs.io/ipfs/')
574+
}
575+
576+
// Matches a protocol (e.g. 'http://' or 'https://') at the start of a string
577+
const PROTOCOL_REGEX = /^([a-z][a-z0-9+\-.]*):\/\//
578+
579+
// If URL already has a protocol, return as is
580+
if (PROTOCOL_REGEX.test(url)) {
581+
return url
582+
}
583+
584+
// Otherwise, assume it's a plain domain and add https://
585+
return `https://${url}`
586+
}

src/rippled/accountTransactions.ts

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface AccountTransactionsResult {
1717
marker?: any
1818
}
1919

20-
const getAccountTransactions = (
20+
const getAccountTransactions = async (
2121
account: string,
2222
currency: string | undefined,
2323
marker: any,
@@ -62,35 +62,39 @@ const getAccountTransactions = (
6262
}
6363

6464
log.info(`get transactions: ${account} -> ${classicAddress}`)
65-
return getAccountTxs(rippledSocket, classicAddress, limit, marker)
66-
.then((data) => {
67-
const transactions = data.transactions
68-
.map((tx: any) => {
69-
const txn = formatTransaction(tx)
70-
return summarize(txn, true)
71-
})
72-
.filter((tx: any) => {
73-
// No filter - return all transactions
74-
if (!currency) {
75-
return true
76-
}
65+
try {
66+
const data = await getAccountTxs(
67+
rippledSocket,
68+
classicAddress,
69+
limit,
70+
marker,
71+
)
72+
const transactions = data.transactions
73+
.map((tx: any) => {
74+
const txn = formatTransaction(tx)
75+
return summarize(txn, true)
76+
})
77+
.filter((tx: any) => {
78+
// No filter - return all transactions
79+
if (!currency) {
80+
return true
81+
}
7782

78-
// Filter by currency (IOU) or MPT issuance ID (passed as currency)
79-
const txString = JSON.stringify(tx)
80-
return (
81-
txString.includes(`"currency":"${currency.toUpperCase()}"`) ||
82-
txString.includes(`"${currency}"`)
83-
)
84-
})
85-
return {
86-
transactions,
87-
marker: data.marker,
88-
}
89-
})
90-
.catch((error: any) => {
91-
log.error(error.toString())
92-
throw error
93-
})
83+
// Filter by currency (IOU) or MPT issuance ID (passed as currency)
84+
const txString = JSON.stringify(tx)
85+
return (
86+
txString.includes(`"currency":"${currency.toUpperCase()}"`) ||
87+
txString.includes(`"${currency}"`)
88+
)
89+
})
90+
return {
91+
transactions,
92+
marker: data.marker,
93+
}
94+
} catch (error: any) {
95+
log.error(error.toString())
96+
throw error
97+
}
9498
}
9599

96100
export default getAccountTransactions

src/rippled/index.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
1-
import getAccountState from './accountState'
2-
import getAccountTransactions from './accountTransactions'
3-
import getLedger from './ledgers'
4-
import getTransaction from './transactions'
5-
import getQuorum from './quorum'
6-
import getNegativeUNL from './nUNL'
7-
import getOffers from './offers'
8-
9-
export {
10-
getAccountState,
11-
getAccountTransactions,
12-
getLedger,
13-
getTransaction,
14-
getQuorum,
15-
getNegativeUNL,
16-
getOffers,
17-
}
1+
export { default as getAccountState } from './accountState'
2+
export { default as getAccountTransactions } from './accountTransactions'
3+
export { default as getLedger } from './ledgers'
4+
export { default as getTransaction } from './transactions'
5+
export { default as getQuorum } from './quorum'
6+
export { default as getNegativeUNL } from './nUNL'
7+
export { default as getOffers } from './offers'
188

199
export { getAccountInfo, getAMMInfoByAssets } from './lib/rippled'

src/rippled/ledgers.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import type { ExplorerXrplClient } from '../containers/shared/SocketContext'
55

66
const log = logger({ name: 'ledgers' })
77

8-
const getLedger = (
8+
const getLedger = async (
99
identifier: string | number,
1010
rippledSocket: ExplorerXrplClient,
11-
) => {
11+
): Promise<any> => {
1212
const parameters: any = {}
1313
if (!isNaN(Number(identifier))) {
1414
parameters.ledger_index = Number(identifier)
@@ -22,13 +22,13 @@ const getLedger = (
2222
}
2323

2424
log.info(`get ledger: ${JSON.stringify(parameters)}`)
25-
return getRippledLedger(rippledSocket, parameters)
26-
.then((ledger) => summarizeLedger(ledger, true))
27-
.then((data) => data)
28-
.catch((error: any) => {
29-
log.error(error.toString())
30-
throw error
31-
})
25+
try {
26+
const ledger = await getRippledLedger(rippledSocket, parameters)
27+
return summarizeLedger(ledger, true)
28+
} catch (error: any) {
29+
log.error(error.toString())
30+
throw error
31+
}
3232
}
3333

3434
export default getLedger

0 commit comments

Comments
 (0)