Skip to content

Commit

Permalink
release: desktop 1.0.2 (#2348)
Browse files Browse the repository at this point in the history
* chore: increment desktop version to 1.0.2-alpha-1

* fix: change GHA node version from 20.x to 20.10.0 (#2340)

* chore: increment shared package version

* rename getDefaultPersistedNetwork to getDefaultStardustNetwork (#2352)

* enhancement: check ipfs gateway health (#2342)

* add default ipfs gateway to profiles + migrations

* improve ipfsgateway table

* remove and set primary gateway

* add input popup

* add validation function

* rewrite ipfs gateway regarding

* fix trailing slash

* increase alpha version

* update ipfsgateways

* improve rewrite ipfs

* download nfts after changing nodes

* add IPFS health check

* add https at start if missing

* improve errormessage

---------

Co-authored-by: Nicole O'Brien <nicole@bloomwallet.io>

* try fix issue with testers

* New Crowdin translations by Github Action (#2354)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>

* enhancement: use list of ipfs gateways as pool and fall backs (#2350)

* get list of urls to download from

* fix sorting

* interrupt queue if url is reached

* rename

* unset prmary

* cleanup code

* fix: add tide to allow list for nfts
add: more ipfs gateways

Co-authored-by: Mark Nardi <nardimark7@gmail.com>

* fix: errors in mint forms

---------

Co-authored-by: Nicole O'Brien <nicole@bloomwallet.io>

* enhancement: improve displayed nft warnings (#2356)

* change invalid media type to error

* improve error messages

* add media type to nft alert

* reverse content type

* fix generic error messages on nfts

* chore: increment desktop version to `1.0.2-alpha-3`

* fix undefined error

* fix setting of primary ipfs node (#2358)

* chore: increment desktop version to `1.0.2`

* fix: fix nfts (#2360)

* fix re-download

* Fix migration of persisted nft data

Co-authored-by: Mark Nardi <nardimark7@gmail.com>

---------

Co-authored-by: Nicole O'Brien <nicole@bloomwallet.io>

* enhancement: add allow list to remote app configuration

* fix: show scam nft warning on already downloaded nfts

* fix: balance breakdown alignment (#2364)

* fix: balance breakdown alignment

* chore: improve type safety

* chore: revert cols & rows

* fix: conversion (#2367)

---------

Co-authored-by: Tuditi <daviddetroch@pm.me>
Co-authored-by: Jean Ribeiro <contact@jeanribeiro.dev>
Co-authored-by: Mark Nardi <nardimark7@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Tuditi <45079109+Tuditi@users.noreply.github.com>
  • Loading branch information
7 people authored Apr 25, 2024
1 parent 02e06a3 commit aae094c
Show file tree
Hide file tree
Showing 70 changed files with 491 additions and 226 deletions.
18 changes: 6 additions & 12 deletions packages/desktop/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import { Popup, ProfileAuthPopup } from '@components/popup'
import TitleBar from '@components/TitleBar.svelte'
import { IS_WINDOWS, Platform, openUrlInBrowser } from '@core/app'
import { registerAppEvents, getAndUpdateDarkMode } from '@core/app/actions'
import {
registerAppEvents,
getAndUpdateDarkMode,
updateAppParametersWithRemoteConfiguration,
} from '@core/app/actions'
import { appSettings, appVersionDetails, initAppSettings, setAppVersionDetails, windowSize } from '@core/app/stores'
import { isLocaleLoaded, localeDirection, setupI18n } from '@core/i18n'
import { checkAndMigrateProfiles, cleanupEmptyProfiles, saveActiveProfile } from '@core/profile/actions'
Expand All @@ -28,9 +32,6 @@
import { _ } from '@core/i18n'
import { getAndUpdateShimmerEvmTokensMetadata } from '@core/market/actions'
import { initializeWalletConnect } from '@auxiliary/wallet-connect/actions'
import { NFT_BLOCKLIST_JSON_URL } from '@core/utils/constants/nft-blocklist-json-url.constant'
import { nftBlocklist } from '@core/utils/stores/nft-blocklist.store'
import nftBlockListJson from '@core/utils/json/nft-blocklist.json'
$: $activeProfile, saveActiveProfile()
Expand Down Expand Up @@ -73,6 +74,7 @@
// Set dark mode initially in case the native theme is already in system
await getAndUpdateDarkMode()
await updateAppParametersWithRemoteConfiguration()
await checkAndMigrateProfiles()
await cleanupEmptyProfiles()
Platform.onEvent('deep-link-request', handleDeepLink)
Expand Down Expand Up @@ -110,14 +112,6 @@
registerMenuButtons()
void initializeWalletConnect()
await getAndUpdateShimmerEvmTokensMetadata()
try {
const response = await fetch(NFT_BLOCKLIST_JSON_URL)
const blocklist = await response.json()
nftBlocklist.set(blocklist)
} catch (error) {
nftBlocklist.set(nftBlockListJson)
}
})
onDestroy(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { openUrlInBrowser } from '@core/app'
import { localize } from '@core/i18n'
import { isEvmNetwork } from '@core/network'
import { IIrc27Nft, Nft, composeUrlFromNftUri, isNftLocked } from '@core/nfts'
import { IIrc27Nft, Nft, getPrimaryNftUrl, isNftLocked, isValidNftUri } from '@core/nfts'
import { updateNftInAllAccountNfts } from '@core/nfts/actions'
import { updatePersistedNft } from '@core/nfts/stores'
import { activeProfile, updateActiveProfile } from '@core/profile/stores'
Expand All @@ -25,7 +25,7 @@
}
function onOpenMediaClick(): void {
openUrlInBrowser(composeUrlFromNftUri(nft?.mediaUrl))
openUrlInBrowser(getPrimaryNftUrl(nft?.mediaUrl))
menu?.close()
}
Expand Down Expand Up @@ -53,7 +53,7 @@
{
icon: IconName.LinkExternal,
title: localize('views.collectibles.details.menu.view'),
disabled: !composeUrlFromNftUri(nft.mediaUrl),
disabled: !isValidNftUri(nft.mediaUrl),
onClick: onOpenMediaClick,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@
unclaimed: BigInt(0),
storageDepositReturn: BigInt(0),
timelock: BigInt(0),
governance: $selectedAccount?.votingPower,
governance: $selectedAccount?.votingPower ?? BigInt(0),
}
let unavailableTotalAmount = $selectedAccount?.votingPower
let unavailableTotalAmount = $selectedAccount?.votingPower ?? BigInt(0)
for (const [outputId, unlocked] of Object.entries(accountBalance?.potentiallyLockedOutputs ?? {})) {
if (unlocked) {
continue
}
const output = (await $selectedAccount.getOutput(outputId)).output
if (output.type === OutputType.Treasury) {
const output = (await $selectedAccount?.getOutput(outputId))?.output
if (output?.type === OutputType.Treasury) {
continue
}
Expand All @@ -65,15 +65,17 @@
const commonOutput = output as CommonOutput
if (containsUnlockCondition(commonOutput.unlockConditions, UnlockConditionType.Expiration)) {
type = UnavailableAmountType.Unclaimed
amount = BigInt(output.amount)
amount = BigInt(output?.amount ?? 0)
} else if (
containsUnlockCondition(commonOutput.unlockConditions, UnlockConditionType.StorageDepositReturn)
) {
type = UnavailableAmountType.StorageDepositReturn
amount = getStorageDepositFromOutput(commonOutput)
} else if (containsUnlockCondition(commonOutput.unlockConditions, UnlockConditionType.Timelock)) {
type = UnavailableAmountType.Timelock
amount = BigInt(output.amount)
amount = BigInt(output?.amount ?? 0)
} else {
continue
}
subBreakdown[type] += amount
Expand All @@ -86,7 +88,7 @@
function getStorageDepositBreakdown(): BalanceBreakdown {
const storageDeposits = accountBalance?.requiredStorageDeposit
const totalStorageDeposit = storageDeposits
? Object.values(accountBalance.requiredStorageDeposit).reduce(
? Object.values(storageDeposits).reduce(
(total: bigint, value: string): bigint => total + BigInt(value ?? 0),
BigInt(0)
)
Expand Down Expand Up @@ -129,10 +131,10 @@
let currentExpandedSection: string
const expanded: { [key: string]: boolean } = {}
function expandOne(breakdownKey) {
function expandOne(breakdownKey: string): void {
if (currentExpandedSection === breakdownKey) {
expanded[currentExpandedSection] = false
currentExpandedSection = undefined
currentExpandedSection = ''
} else {
expanded[currentExpandedSection] = false
expanded[breakdownKey] = true
Expand Down
6 changes: 3 additions & 3 deletions packages/desktop/components/popup/popups/InputPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
type InputProp = {
placeholder: string
startValue: string
validate: (text: string) => void
validate: (text: string) => Promise<void>
}
export let variant: 'primary' | 'success' | 'warning' | 'danger' | 'info' = 'primary'
export let title: string
export let description: string = ''
export let input: InputProp = { placeholder: '', startValue: '', validate: () => {} }
export let input: InputProp = { placeholder: '', startValue: '', validate: async () => {} }
export let backText: string = localize('actions.cancel')
export let confirmText: string = localize('actions.confirm')
export let onConfirm: (inputText: string) => Promise<void>
Expand All @@ -29,7 +29,7 @@
if (onConfirm) {
errorText = ''
try {
input.validate(inputText)
await input.validate(inputText)
await onConfirm(inputText)
} catch (error) {
errorText = error as string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { BaseError } from '@core/error/classes'
import { localize } from '@core/i18n'
import { NftStandard, composeUrlFromNftUri } from '@core/nfts'
import { NftStandard, getPrimaryNftUrl } from '@core/nfts'
import { MimeType } from '@core/nfts/enums'
import { fetchWithTimeout } from '@core/nfts/utils/fetchWithTimeout'
import { HttpHeader } from '@core/utils'
Expand Down Expand Up @@ -65,7 +65,7 @@
}
async function validate(): Promise<boolean> {
if (name.length === 0) {
if (!name || name.length === 0) {
nameError = localize('popups.mintNftForm.errors.emptyName')
}
Expand All @@ -78,15 +78,20 @@
}
}
if (uri.length === 0 || !isValidUri(uri)) {
if (!uri || uri.length === 0 || !isValidUri(uri)) {
uriError = localize('popups.mintNftForm.errors.invalidURI')
} else {
try {
const response = await fetchWithTimeout(composeUrlFromNftUri(uri), 1, { method: 'HEAD' })
if (response.status === 200 || response.status === 304) {
type = response.headers.get(HttpHeader.ContentType)
const downloadUrl = getPrimaryNftUrl(uri)
if (downloadUrl) {
const response = await fetchWithTimeout(downloadUrl, 1, { method: 'HEAD' })
if (response.status === 200 || response.status === 304) {
type = response.headers.get(HttpHeader.ContentType) as MimeType
} else {
uriError = localize('popups.mintNftForm.errors.notReachable')
}
} else {
uriError = localize('popups.mintNftForm.errors.notReachable')
uriError = localize('popups.mintNftForm.errors.invalidURI')
}
} catch (err) {
uriError = localize('popups.mintNftForm.errors.notReachable')
Expand Down
23 changes: 13 additions & 10 deletions packages/desktop/components/popup/popups/MintNftFormPopup.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { BaseError } from '@core/error/classes'
import { localize } from '@core/i18n'
import { composeUrlFromNftUri, NftStandard } from '@core/nfts'
import { getPrimaryNftUrl, NftStandard } from '@core/nfts'
import { MimeType } from '@core/nfts/enums'
import { fetchWithTimeout } from '@core/nfts/utils/fetchWithTimeout'
import { getNetworkHrp } from '@core/profile/actions'
Expand Down Expand Up @@ -106,7 +106,7 @@
}
async function validate(): Promise<boolean> {
if (name.length === 0) {
if (!name || name.length === 0) {
nameError = localize('popups.mintNftForm.errors.emptyName')
}
Expand All @@ -119,18 +119,21 @@
}
}
const dummyUri = uri.replace('{id}', '1')
if (uri.length === 0 || !isValidUri(dummyUri)) {
const dummyUri = uri?.replace('{id}', '1')
if (!uri || uri.length === 0 || !dummyUri || !isValidUri(dummyUri)) {
uriError = localize('popups.mintNftForm.errors.invalidURI')
} else {
try {
const response = await fetchWithTimeout(composeUrlFromNftUri(dummyUri), 1, {
method: 'HEAD',
})
if (response.status === 200 || response.status === 304) {
type = response.headers.get(HttpHeader.ContentType) as MimeType
const downloadUrl = getPrimaryNftUrl(dummyUri)
if (downloadUrl) {
const response = await fetchWithTimeout(downloadUrl, 1, { method: 'HEAD' })
if (response.status === 200 || response.status === 304) {
type = response.headers.get(HttpHeader.ContentType) as MimeType
} else {
uriError = localize('popups.mintNftForm.errors.notReachable')
}
} else {
uriError = localize('popups.mintNftForm.errors.notReachable')
uriError = localize('popups.mintNftForm.errors.invalidURI')
}
} catch (err) {
uriError = localize('popups.mintNftForm.errors.notReachable')
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "desktop",
"productName": "Bloom",
"version": "1.0.2-alpha-1",
"version": "1.0.2",
"description": "Simple and secure web3 wallet for the IOTA and Shimmer ecosystem",
"main": "public/build/main.process.js",
"repository": "git@github.com:bloomwalletio/bloom.git",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
<NftMediaAlert
type={nft.downloadMetadata?.error?.type ?? nft.downloadMetadata?.warning?.type}
message={nft.downloadMetadata?.error?.message ?? nft.downloadMetadata?.warning?.message}
downloadMetadata={nft.downloadMetadata}
{nft}
/>
</error-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@
}
</script>

<CollectibleDetails {nft} {details} attributes={nft.metadata.attributes} {explorerEndpoint} />
<CollectibleDetails {nft} {details} attributes={nft.metadata?.attributes} {explorerEndpoint} />
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<script lang="ts">
import { DownloadErrorType, DownloadWarningType, Nft, NftDownloadOptions } from '@core/nfts'
import { DownloadErrorType, DownloadWarningType, IDownloadMetadata, Nft, NftDownloadOptions } from '@core/nfts'
import { Alert, Link, Text } from '@bloomwalletio/ui'
import { localize } from '@core/i18n'
import { addNftsToDownloadQueue, updateNftInAllAccountNfts } from '@core/nfts/actions'
import { getFormattedFileSize } from '@core/utils'
export let type: DownloadErrorType | DownloadWarningType | undefined
export let message: string | undefined
export let downloadMetadata: IDownloadMetadata
export let nft: Nft
let alertText = ''
$: type, message, (alertText = getAlertText())
$: variant = Object.values(DownloadErrorType).some((_type) => _type === type) ? 'danger' : 'warning'
$: alertText = type === 'generic' ? message : localize(`error.nft.${type}.long`)
const retryableErrors = [
DownloadErrorType.NotReachable,
Expand All @@ -19,6 +22,24 @@
DownloadWarningType.TooLargeFile,
]
function getAlertText(): string {
switch (type) {
case DownloadErrorType.Generic:
return downloadMetadata.responseCode + ' ' + message
case DownloadErrorType.NotMatchingFileTypes:
return localize('error.nft.notMatchingFileTypes.long', {
expected: nft.metadata?.type,
actual: downloadMetadata.contentType,
})
case DownloadWarningType.TooLargeFile:
return (
localize(`error.nft.${type}.long`) +
` - ${getFormattedFileSize(Number(downloadMetadata.contentLength ?? 0))}`
)
default:
return localize(`error.nft.${type}.long`)
}
}
function onDownloadClick(): void {
let options: Partial<NftDownloadOptions> = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<SelectInput
label={localize('views.settings.downloadNftPermissions.input')}
bind:selected
value={selected.value}
value={selected?.value}
{options}
hideValue
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,45 @@
import { Button, IconName, Pill, Text } from '@bloomwalletio/ui'
import { IpfsGatewayMenu } from './components'
import { PopupId, closePopup, openPopup } from '@desktop/auxiliary/popup'
import { isValidUrl, stripTrailingSlash } from '@core/utils'
import { addNftsToDownloadQueue } from '@core/nfts/actions'
import { selectedAccountNfts } from '@core/nfts/stores'
import { isValidUrl } from '@core/utils'
import { IPFS_HEALTH_CHECKER_PATH } from '@core/profile/constants'
function addIpfsGateway(url: string): void {
function addIpfsGateway(inputtedUrl: string): void {
const url = new URL(getOriginFromInputtedUrl(inputtedUrl)).origin
const nftSettings = $activeProfile?.settings.nfts
const ipfsGateways =
nftSettings.ipfsGateways?.map((ipfsGateway) => ({
...ipfsGateway,
isPrimary: ipfsGateway.url === url,
})) ?? []
if (!nftSettings.ipfsGateways?.some((ipfsGateway) => ipfsGateway.url === url)) {
ipfsGateways.push({ url, isPrimary: true })
const ipfsGateways = nftSettings.ipfsGateways ?? []
if (!ipfsGateways.some((ipfsGateway) => ipfsGateway.url === url)) {
ipfsGateways.push({ url, isPrimary: false })
}
updateActiveProfileSettings({ nfts: { ...$activeProfile?.settings.nfts, ipfsGateways } })
void addNftsToDownloadQueue($selectedAccountNfts)
}
function validateIpfsGateway(url: string): void {
async function validateIpfsGateway(_url: string): Promise<void> {
const url = getOriginFromInputtedUrl(_url)
if (!url || !isValidUrl(url)) {
throw localize('error.global.invalidUrl')
return Promise.reject(localize('error.global.invalidUrl'))
}
try {
const ipfsHealthCheckUrl = new URL(IPFS_HEALTH_CHECKER_PATH, url)
const response = await fetch(ipfsHealthCheckUrl, { method: 'HEAD' })
if (!response.ok) {
return Promise.reject(localize('views.settings.ipfsGateways.addGateway.error.invalidGateway'))
}
} catch (error) {
return Promise.reject(localize('views.settings.ipfsGateways.addGateway.error.notReachable'))
}
}
function getOriginFromInputtedUrl(inputtedUrl: string): string {
return inputtedUrl.startsWith('http://') || inputtedUrl.startsWith('https://')
? inputtedUrl.trim()
: `https://${inputtedUrl.trim()}`
}
function onIpfsGatewayAdd(): void {
Expand All @@ -42,7 +57,7 @@
validate: validateIpfsGateway,
},
onConfirm: (inputText: string) => {
addIpfsGateway(stripTrailingSlash(inputText))
addIpfsGateway(inputText)
closePopup()
},
},
Expand Down
Loading

0 comments on commit aae094c

Please sign in to comment.