Skip to content

Commit

Permalink
Improve error messages
Browse files Browse the repository at this point in the history
Always try to properly differentiate between:
 - Illegal request (wrong address etc)
 - Failure to load data
 - Data not found
  • Loading branch information
csillag committed Jan 27, 2024
1 parent d54e70c commit fe7fce9
Show file tree
Hide file tree
Showing 14 changed files with 74 additions and 21 deletions.
1 change: 1 addition & 0 deletions .changelog/1124.trivial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve error messages for network problems / missing data
8 changes: 8 additions & 0 deletions src/app/components/ErrorDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ type FormattedError = { title: string; message: ReactNode }
const errorMap: Record<AppErrors, (t: TFunction, error: ErrorPayload) => FormattedError> = {
[AppErrors.Unknown]: (t, error) => ({ title: t('errors.unknown'), message: error.message }),
[AppErrors.InvalidAddress]: t => ({ title: t('errors.invalidAddress'), message: t('errors.validateURL') }),
[AppErrors.CannotLoadData]: t => ({
title: t('errors.canNotLoadData'),
message: t('errors.canNotReachDataSource'),
}),
[AppErrors.InvalidBlockHeight]: t => ({
title: t('errors.invalidBlockHeight'),
message: t('errors.validateURL'),
Expand Down Expand Up @@ -44,6 +48,10 @@ const errorMap: Record<AppErrors, (t: TFunction, error: ErrorPayload) => Formatt
title: t('errors.notFoundBlockHeight'),
message: t('errors.validateURL'),
}),
[AppErrors.NotFoundTokenAddress]: t => ({
title: t('errors.notFoundToken'),
message: t('errors.validateURL'),
}),
[AppErrors.NotFoundTxHash]: t => ({ title: t('errors.notFoundTx'), message: t('errors.validateURL') }),
[AppErrors.InvalidUrl]: t => ({ title: t('errors.invalidUrl'), message: t('errors.validateURL') }),
[AppErrors.UnsupportedLayer]: t => ({
Expand Down
3 changes: 3 additions & 0 deletions src/app/pages/AccountDetailsPage/AccountDetailsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TokenPriceInfo } from '../../../coin-gecko/api'
type AccountDetailsProps = {
isLoading: boolean
isError: boolean
errorCode: any
isContract: boolean
account: RuntimeAccount | undefined
token: EvmToken | undefined
Expand All @@ -17,6 +18,7 @@ type AccountDetailsProps = {
export const AccountDetailsCard: FC<AccountDetailsProps> = ({
isLoading,
isError,
errorCode,
isContract,
account,
token,
Expand All @@ -32,6 +34,7 @@ export const AccountDetailsCard: FC<AccountDetailsProps> = ({
<AccountDetailsView
isLoading={isLoading}
isError={isError}
errorCode={errorCode}
account={account}
token={token}
tokenPriceInfo={tokenPriceInfo}
Expand Down
16 changes: 12 additions & 4 deletions src/app/pages/AccountDetailsPage/AccountDetailsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,23 @@ import { Account } from '../../components/Account'
export const AccountDetailsView: FC<{
isLoading: boolean
isError: boolean
errorCode: any
account: RuntimeAccount | undefined
token?: EvmToken
tokenPriceInfo: TokenPriceInfo
showLayer?: boolean
}> = ({ isLoading, isError, account, token, tokenPriceInfo, showLayer }) => {
}> = ({ isLoading, isError, errorCode, account, token, tokenPriceInfo, showLayer }) => {
const { t } = useTranslation()
return isError ? (
<CardEmptyState label={t('account.cantLoadDetails')} />
) : (
if (isError) {
switch (errorCode) {
case 'ERR_NETWORK':
return <CardEmptyState label={t('account.cantLoadDetails')} />
default:
// TODO: what other error cases do we have?
console.log('Error code is', errorCode)
}
}
return (
<Account
account={account}
token={token}
Expand Down
6 changes: 4 additions & 2 deletions src/app/pages/AccountDetailsPage/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ export const useAccount = (scope: SearchScope, address: string) => {
const query = useGetRuntimeAccountsAddress(network, layer, address)
const account = query.data?.data

const { isLoading, isError, isFetched } = query
const { isLoading, isError, isFetched, error } = query

return { account, isLoading, isError, isFetched }
const errorCode = (error as any)?.code

return { account, isLoading, isError, errorCode, isFetched }
}

export const useAccountTransactions = (scope: SearchScope, address: string) => {
Expand Down
3 changes: 2 additions & 1 deletion src/app/pages/AccountDetailsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const AccountDetailsPage: FC = () => {

const scope = useRequiredScopeParam()
const address = useLoaderData() as string
const { account, isLoading: isAccountLoading, isError } = useAccount(scope, address)
const { account, isLoading: isAccountLoading, isError, errorCode } = useAccount(scope, address)
const isContract = !!account?.evm_contract
const { token, isLoading: isTokenLoading } = useTokenInfo(scope, address, isContract)

Expand All @@ -57,6 +57,7 @@ export const AccountDetailsPage: FC = () => {
<AccountDetailsCard
isLoading={isLoading}
isError={isError}
errorCode={errorCode}
isContract={isContract}
account={account}
token={token}
Expand Down
13 changes: 11 additions & 2 deletions src/app/pages/BlockDetailPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@ export const BlockDetailPage: FC = () => {
// We should use useGetConsensusBlocksHeight()
}
const blockHeight = parseInt(useParams().blockHeight!, 10)
const { isLoading, data } = useGetRuntimeBlockByHeight(
const { isLoading, data, error } = useGetRuntimeBlockByHeight(
scope.network,
scope.layer, // This is OK, since consensus is already handled separately
blockHeight,
)
if (!data && !isLoading) {

if (!data?.data && !isLoading) {
const errorCode = (error as any)?.code
switch (errorCode) {
case 'ERR_NETWORK':
throw AppErrors.CannotLoadData
default:
// TODO: look for other error codes, too.
// (Currently we are not aware of anything else)
}
throw AppErrors.NotFoundBlockHeight
}
const block = data?.data
Expand Down
2 changes: 2 additions & 0 deletions src/app/pages/SearchResultsPage/SearchResultsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const SearchResultsList: FC<{
<AccountDetailsView
isLoading={false}
isError={false}
errorCode={undefined}
account={item}
tokenPriceInfo={tokenPrices[item.network]}
showLayer={true}
Expand All @@ -98,6 +99,7 @@ export const SearchResultsList: FC<{
<AccountDetailsView
isLoading={false}
isError={false}
errorCode={undefined}
account={item}
tokenPriceInfo={tokenPrices[item.network]}
showLayer={true}
Expand Down
3 changes: 2 additions & 1 deletion src/app/pages/TokenDashboardPage/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ export const useTokenInfo = (scope: SearchScope, address: string, enabled = true
query: { enabled },
})
const token = query.data?.data
const { isLoading, isError, isFetched } = query
const { isLoading, isError, error, isFetched } = query
return {
token,
isLoading: isLoading && enabled, // By default, we get true for isLoading on disabled queries. We don't want that.
isError,
errorCode: (error as any)?.code,
isFetched,
}
}
Expand Down
14 changes: 12 additions & 2 deletions src/app/pages/TokenDashboardPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,20 @@ export const TokenDashboardPage: FC = () => {
const scope = useRequiredScopeParam()
const address = useLoaderData() as string

const { token, isError } = useTokenInfo(scope, address)
const { token, isError, errorCode } = useTokenInfo(scope, address)

if (isError) {
throw AppErrors.InvalidAddress
switch (errorCode) {
case 'ERR_NETWORK':
throw AppErrors.CannotLoadData
case 'ERR_BAD_REQUEST':
throw AppErrors.NotFoundTokenAddress
default:
// TODO: look for other error codes, too
// (Currently we are not aware of anything else.)
console.log('Error code is', errorCode)
throw AppErrors.NotFoundTokenAddress
}
}

const tokenTransfersLink = useHref(``)
Expand Down
13 changes: 11 additions & 2 deletions src/app/pages/TransactionDetailPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const TransactionDetailPage: FC = () => {
AddressSwitchOption.Oasis | AddressSwitchOption.ETH
>(AddressSwitchOption.ETH)

const { isLoading, data } = useGetRuntimeTransactionsTxHash(
const { isLoading, data, error } = useGetRuntimeTransactionsTxHash(
scope.network,
scope.layer, // This is OK since consensus has been handled separately
hash,
Expand All @@ -105,7 +105,16 @@ export const TransactionDetailPage: FC = () => {
const tokenPriceInfo = useTokenPrice(getTickerForNetwork(scope.network))

if (!transaction && !isLoading) {
throw AppErrors.NotFoundTxHash
const errorCode = (error as any)?.code
switch (errorCode) {
case 'ERR_NETWORK':
throw AppErrors.CannotLoadData
default:
// TODO: what other error codes are there?
// (We are not aware of anything else)
console.log('Error code is', errorCode)
throw AppErrors.NotFoundTxHash
}
}
return (
<PageLayout>
Expand Down
3 changes: 3 additions & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@
"value": "{{value, number}}"
},
"errors": {
"canNotLoadData": "Can not load data",
"canNotReachDataSource": "We were unable to reach the data source to request this data. This is probably a temporary (network?) problem. Please try again later.",
"code": "error code",
"error": "Error",
"loadFirstPage": "load the first page",
Expand All @@ -177,6 +179,7 @@
"invalidPageNumber": "Invalid page number",
"invalidTxHash": "Invalid transaction hash",
"notFoundBlockHeight": "Block not found",
"notFoundToken": "Token not found",
"notFoundTx": "Transaction not found",
"pageDoesNotExist": "The page you are looking for does not exist.",
"validateURL": "Please validate provided URL",
Expand Down
8 changes: 1 addition & 7 deletions src/oasis-nexus/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -497,13 +497,7 @@ export function useGetRuntimeBlockByHeight(
if (status !== 200) return data
const block = data.blocks[0]
if (!block || block.round !== blockHeight) {
throw new axios.AxiosError('not found', 'ERR_BAD_REQUEST', this, null, {
status: 404,
statusText: 'not found',
config: this,
data: 'not found',
headers: {},
})
return undefined
}
return {
...block,
Expand Down
2 changes: 2 additions & 0 deletions src/types/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ export enum AppErrors {
PageDoesNotExist = 'page_does_not_exist',
NotFoundBlockHeight = 'not_found_block_height',
NotFoundTxHash = 'not_found_tx_hash',
NotFoundTokenAddress = 'not_found_token_address',
InvalidUrl = 'invalid_url',
Storage = 'storage',
CannotLoadData = 'cannot_load_data',
}

export interface ErrorPayload {
Expand Down

0 comments on commit fe7fce9

Please sign in to comment.