Show wallets query error (#2284)

* Show wallets query error to user

* Also show decryption errors to user
This commit is contained in:
ekzyis 2025-07-16 17:11:52 +02:00 committed by GitHub
parent d670b38d1d
commit 45d7eaf1bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 5 deletions

View File

@ -68,6 +68,19 @@ export default function Wallet () {
) )
} }
if (status instanceof Error) {
return (
<WalletLayout>
<div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1'>
<span className='text-muted fw-bold my-1'>failed to load wallets</span>
<small className='d-block text-muted'>
{status.message}
</small>
</div>
</WalletLayout>
)
}
if (status === Status.NO_WALLETS && !showWallets) { if (status === Status.NO_WALLETS && !showWallets) {
return ( return (
<WalletLayout> <WalletLayout>

View File

@ -9,7 +9,7 @@ import {
useWalletMigrationMutation, CryptoKeyRequiredError, useIsWrongKey useWalletMigrationMutation, CryptoKeyRequiredError, useIsWrongKey
} from '@/wallets/client/hooks' } from '@/wallets/client/hooks'
import { WalletConfigurationError } from '@/wallets/client/errors' import { WalletConfigurationError } from '@/wallets/client/errors'
import { SET_WALLETS, WRONG_KEY, KEY_MATCH, NO_KEY, useWalletsDispatch } from '@/wallets/client/context' import { SET_WALLETS, WRONG_KEY, KEY_MATCH, NO_KEY, useWalletsDispatch, WALLETS_QUERY_ERROR } from '@/wallets/client/context'
import { useIndexedDB } from '@/components/use-indexeddb' import { useIndexedDB } from '@/components/use-indexeddb'
export function useServerWallets () { export function useServerWallets () {
@ -19,6 +19,7 @@ export function useServerWallets () {
useEffect(() => { useEffect(() => {
if (query.error) { if (query.error) {
console.error('failed to fetch wallets:', query.error) console.error('failed to fetch wallets:', query.error)
dispatch({ type: WALLETS_QUERY_ERROR, error: query.error })
return return
} }
if (query.loading) return if (query.loading) return

View File

@ -15,6 +15,7 @@ export const SET_KEY = 'SET_KEY'
export const WRONG_KEY = 'WRONG_KEY' export const WRONG_KEY = 'WRONG_KEY'
export const KEY_MATCH = 'KEY_MATCH' export const KEY_MATCH = 'KEY_MATCH'
export const NO_KEY = 'KEY_UNAVAILABLE' export const NO_KEY = 'KEY_UNAVAILABLE'
export const WALLETS_QUERY_ERROR = 'WALLETS_QUERY_ERROR'
export default function reducer (state, action) { export default function reducer (state, action) {
switch (action.type) { switch (action.type) {
@ -32,6 +33,11 @@ export default function reducer (state, action) {
templates templates
} }
} }
case WALLETS_QUERY_ERROR:
return {
...state,
status: transitionStatus(action, state, action.error)
}
case SET_KEY: case SET_KEY:
return { return {
...state, ...state,
@ -61,10 +67,10 @@ export default function reducer (state, action) {
function transitionStatus ({ type }, { status: from }, to) { function transitionStatus ({ type }, { status: from }, to) {
switch (type) { switch (type) {
case SET_WALLETS: { case SET_WALLETS: {
return [Status.PASSPHRASE_REQUIRED, Status.WALLETS_UNAVAILABLE].includes(from) ? from : to return (from instanceof Error || [Status.PASSPHRASE_REQUIRED, Status.WALLETS_UNAVAILABLE].includes(from)) ? from : to
} }
case KEY_MATCH: { case KEY_MATCH: {
return from === Status.LOADING_WALLETS ? from : to return (from instanceof Error || from === Status.LOADING_WALLETS) ? from : to
} }
default: default:
return to return to

View File

@ -38,6 +38,7 @@ export function useWalletsQuery () {
const { me } = useMe() const { me } = useMe()
const query = useQuery(WALLETS, { skip: !me }) const query = useQuery(WALLETS, { skip: !me })
const [wallets, setWallets] = useState(null) const [wallets, setWallets] = useState(null)
const [error, setError] = useState(null)
const { decryptWallet, ready } = useWalletDecryption() const { decryptWallet, ready } = useWalletDecryption()
@ -48,10 +49,14 @@ export function useWalletsQuery () {
) )
.then(wallets => wallets.map(protocolCheck)) .then(wallets => wallets.map(protocolCheck))
.then(wallets => wallets.map(undoFieldAlias)) .then(wallets => wallets.map(undoFieldAlias))
.then(wallets => setWallets(wallets)) .then(wallets => {
setWallets(wallets)
setError(null)
})
.catch(err => { .catch(err => {
console.error('failed to decrypt wallets:', err) console.error('failed to decrypt wallets:', err)
setWallets([]) setWallets([])
setError(new Error('decryption error: ' + err.message))
}) })
}, [query.data, decryptWallet, ready]) }, [query.data, decryptWallet, ready])
@ -59,9 +64,10 @@ export function useWalletsQuery () {
return useMemo(() => ({ return useMemo(() => ({
...query, ...query,
error: error ?? query.error,
loading: !wallets, loading: !wallets,
data: wallets ? { wallets } : null data: wallets ? { wallets } : null
}), [query, wallets]) }), [query, error, wallets])
} }
function protocolCheck (wallet) { function protocolCheck (wallet) {