Add error stakcs to useCall & ErrorBoundary (#6447)
This commit is contained in:
parent
5958a96a26
commit
60a5334ff2
@ -27,8 +27,14 @@ function extractLists (value: Campaign[] | null, leasePeriod?: LeasePeriod): [Ca
|
||||
let allIds: ParaId[] | null = null;
|
||||
|
||||
if (value && currentPeriod) {
|
||||
active = value.filter(({ firstSlot, isCapped, isEnded, isWinner }) => !(isCapped || isEnded || isWinner) && currentPeriod.lte(firstSlot));
|
||||
ended = value.filter(({ firstSlot, isCapped, isEnded, isWinner }) => (isCapped || isEnded || isWinner) || currentPeriod.gt(firstSlot));
|
||||
active = value.filter(({ firstSlot, isCapped, isEnded, isWinner }) =>
|
||||
!(isCapped || isEnded || isWinner) &&
|
||||
currentPeriod.lte(firstSlot)
|
||||
);
|
||||
ended = value.filter(({ firstSlot, isCapped, isEnded, isWinner }) =>
|
||||
(isCapped || isEnded || isWinner) ||
|
||||
currentPeriod.gt(firstSlot)
|
||||
);
|
||||
allIds = value.map(({ paraId }) => paraId);
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import type { Balance, ParaId } from '@polkadot/types/interfaces';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useAccounts, useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { useAccounts, useApi, useCall, useNamedHook } from '@polkadot/react-hooks';
|
||||
import { encodeAddress } from '@polkadot/util-crypto';
|
||||
|
||||
interface Result extends DeriveContributions {
|
||||
@ -25,7 +25,7 @@ const NO_CONTRIB: Result = {
|
||||
myContributions: {}
|
||||
};
|
||||
|
||||
export default function useContributions (paraId: ParaId): Result {
|
||||
function useContributionsImpl (paraId: ParaId): Result {
|
||||
const { api } = useApi();
|
||||
const { allAccountsHex } = useAccounts();
|
||||
const [state, setState] = useState<Result>(() => NO_CONTRIB);
|
||||
@ -57,3 +57,7 @@ export default function useContributions (paraId: ParaId): Result {
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export default function useContributions (paraId: ParaId): Result {
|
||||
return useNamedHook('useContributions', useContributionsImpl, paraId);
|
||||
}
|
||||
|
||||
@ -7,9 +7,9 @@ import type { ProposalExt, ScheduledProposals } from '../types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { useApi, useCall, useNamedHook } from '@polkadot/react-hooks';
|
||||
|
||||
export default function useProposal (id: ParaId, approvedIds: ParaId[], scheduled: ScheduledProposals[]): ProposalExt {
|
||||
function useProposalImpl (id: ParaId, approvedIds: ParaId[], scheduled: ScheduledProposals[]): ProposalExt {
|
||||
const { api } = useApi();
|
||||
const opt = useCall<Option<ParachainProposal>>(api.query.proposeParachain.proposals, [id]);
|
||||
|
||||
@ -25,3 +25,7 @@ export default function useProposal (id: ParaId, approvedIds: ParaId[], schedule
|
||||
[approvedIds, id, opt, scheduled]
|
||||
);
|
||||
}
|
||||
|
||||
export default function useProposal (id: ParaId, approvedIds: ParaId[], scheduled: ScheduledProposals[]): ProposalExt {
|
||||
return useNamedHook('useProposal', useProposalImpl, id, approvedIds, scheduled);
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import type { QueuedAction } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { useApi, useCall, useNamedHook } from '@polkadot/react-hooks';
|
||||
import { BN_EIGHT, BN_FIVE, BN_FOUR, BN_NINE, BN_ONE, BN_SEVEN, BN_SIX, BN_TEN, BN_THREE, BN_TWO } from '@polkadot/util';
|
||||
|
||||
const INC = [BN_ONE, BN_TWO, BN_THREE, BN_FOUR, BN_FIVE, BN_SIX, BN_SEVEN, BN_EIGHT, BN_NINE, BN_TEN];
|
||||
@ -16,7 +16,7 @@ const callOpts = {
|
||||
withParams: true
|
||||
};
|
||||
|
||||
export default function useActionsQueue (): QueuedAction[] {
|
||||
function useActionsQueueImpl (): QueuedAction[] {
|
||||
const { api } = useApi();
|
||||
const currentIndex = useCall<SessionIndex>(api.query.session.currentIndex);
|
||||
const queryIndexes = useMemo(() => currentIndex && INC.map((i) => currentIndex.add(i)), [currentIndex]);
|
||||
@ -35,3 +35,7 @@ export default function useActionsQueue (): QueuedAction[] {
|
||||
[nextActions]
|
||||
);
|
||||
}
|
||||
|
||||
export default function useActionsQueue (): QueuedAction[] {
|
||||
return useNamedHook('useActionsQueue', useActionsQueueImpl);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import type { AuctionIndex, BlockNumber, LeasePeriodOf } from '@polkadot/types/i
|
||||
import type { ITuple } from '@polkadot/types/types';
|
||||
import type { AuctionInfo } from './types';
|
||||
|
||||
import { useApi, useCallMulti } from '@polkadot/react-hooks';
|
||||
import { useApi, useCallMulti, useNamedHook } from '@polkadot/react-hooks';
|
||||
|
||||
const optionsMulti = {
|
||||
transform: ([numAuctions, optInfo]: [AuctionIndex, Option<ITuple<[LeasePeriodOf, BlockNumber]>>]): AuctionInfo => {
|
||||
@ -20,7 +20,7 @@ const optionsMulti = {
|
||||
}
|
||||
};
|
||||
|
||||
export default function useAuctionInfo (): AuctionInfo | undefined {
|
||||
function useAuctionInfoImpl (): AuctionInfo | undefined {
|
||||
const { api } = useApi();
|
||||
|
||||
return useCallMulti<AuctionInfo>([
|
||||
@ -28,3 +28,7 @@ export default function useAuctionInfo (): AuctionInfo | undefined {
|
||||
api.query.auctions?.auctionInfo
|
||||
], optionsMulti);
|
||||
}
|
||||
|
||||
export default function useAuctionInfo (): AuctionInfo | undefined {
|
||||
return useNamedHook('useAuctionInfo', useAuctionInfoImpl);
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import type { Campaign, Campaigns } from './types';
|
||||
import BN from 'bn.js';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useApi, useBestNumber, useCall, useEventTrigger, useIsMountedRef, useMapKeys } from '@polkadot/react-hooks';
|
||||
import { useApi, useBestNumber, useCall, useEventTrigger, useIsMountedRef, useMapKeys, useNamedHook } from '@polkadot/react-hooks';
|
||||
import { BN_ZERO, u8aConcat } from '@polkadot/util';
|
||||
import { encodeAddress } from '@polkadot/util-crypto';
|
||||
|
||||
@ -152,7 +152,7 @@ function extractFundIds (keys: StorageKey<[ParaId]>[]): ParaId[] {
|
||||
return keys.map(({ args: [paraId] }) => paraId);
|
||||
}
|
||||
|
||||
export default function useFunds (): Campaigns {
|
||||
function useFundsImpl (): Campaigns {
|
||||
const { api } = useApi();
|
||||
const bestNumber = useBestNumber();
|
||||
const mountedRef = useIsMountedRef();
|
||||
@ -171,3 +171,7 @@ export default function useFunds (): Campaigns {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function useFunds (): Campaigns {
|
||||
return useNamedHook('useFunds', useFundsImpl);
|
||||
}
|
||||
|
||||
@ -6,10 +6,10 @@ import type { LeasePeriod } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useApi, useBestNumber } from '@polkadot/react-hooks';
|
||||
import { useApi, useBestNumber, useNamedHook } from '@polkadot/react-hooks';
|
||||
import { BN_ZERO } from '@polkadot/util';
|
||||
|
||||
export default function useLeasePeriod (): LeasePeriod | undefined {
|
||||
function useLeasePeriodImpl (): LeasePeriod | undefined {
|
||||
const { api } = useApi();
|
||||
const bestNumber = useBestNumber();
|
||||
|
||||
@ -30,3 +30,7 @@ export default function useLeasePeriod (): LeasePeriod | undefined {
|
||||
};
|
||||
}, [api, bestNumber]);
|
||||
}
|
||||
|
||||
export default function useLeasePeriod (): LeasePeriod | undefined {
|
||||
return useNamedHook('useLeasePeriod', useLeasePeriodImpl);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import type { u32 } from '@polkadot/types';
|
||||
import BN from 'bn.js';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
import { useApi, useNamedHook } from '@polkadot/react-hooks';
|
||||
|
||||
const RANGES_DEFAULT: [number, number][] = [
|
||||
[0, 0], [0, 1], [0, 2], [0, 3],
|
||||
@ -19,7 +19,7 @@ function isU32 (leasePeriodsPerSlot: unknown): leasePeriodsPerSlot is u32 {
|
||||
return !!leasePeriodsPerSlot;
|
||||
}
|
||||
|
||||
export function useLeaseRanges (): [number, number][] {
|
||||
function useLeaseRangesImpl (): [number, number][] {
|
||||
const { api } = useApi();
|
||||
|
||||
return useMemo(
|
||||
@ -42,7 +42,11 @@ export function useLeaseRanges (): [number, number][] {
|
||||
);
|
||||
}
|
||||
|
||||
export function useLeaseRangeMax (): BN {
|
||||
export function useLeaseRanges (): [number, number][] {
|
||||
return useNamedHook('useLeaseRanges', useLeaseRangesImpl);
|
||||
}
|
||||
|
||||
function useLeaseRangeMaxImpl (): BN {
|
||||
const ranges = useLeaseRanges();
|
||||
|
||||
return useMemo(
|
||||
@ -50,3 +54,7 @@ export function useLeaseRangeMax (): BN {
|
||||
[ranges]
|
||||
);
|
||||
}
|
||||
|
||||
export function useLeaseRangeMax (): BN {
|
||||
return useNamedHook('useLeaseRangeMax', useLeaseRangeMaxImpl);
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import type { OwnedId, OwnedIdPartial } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useAccounts, useApi, useCall, useEventTrigger, useMapEntries } from '@polkadot/react-hooks';
|
||||
import { useAccounts, useApi, useCall, useEventTrigger, useMapEntries, useNamedHook } from '@polkadot/react-hooks';
|
||||
|
||||
interface CodeHash {
|
||||
hash: Hash | null;
|
||||
@ -52,7 +52,7 @@ const hashesOption = {
|
||||
withParamsTransform: true
|
||||
};
|
||||
|
||||
export default function useOwnedIds (): OwnedId[] {
|
||||
function useOwnedIdsImpl (): OwnedId[] {
|
||||
const { api } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
const trigger = useEventTrigger([api.events.registrar.Registered, api.events.registrar.Reserved]);
|
||||
@ -71,3 +71,7 @@ export default function useOwnedIds (): OwnedId[] {
|
||||
[allAccounts, hashes, unfiltered]
|
||||
);
|
||||
}
|
||||
|
||||
export default function useOwnedIds (): OwnedId[] {
|
||||
return useNamedHook('useOwnedIds', useOwnedIdsImpl);
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import type { Proposals } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useApi, useCallMulti, useEventTrigger, useIsMountedRef, useMapEntries, useMapKeys } from '@polkadot/react-hooks';
|
||||
import { useApi, useCallMulti, useEventTrigger, useIsMountedRef, useMapEntries, useMapKeys, useNamedHook } from '@polkadot/react-hooks';
|
||||
|
||||
type MultiQuery = [SessionIndex | undefined, ParaId[] | undefined];
|
||||
|
||||
@ -31,7 +31,7 @@ function extractScheduled (entries: [StorageKey<[SessionIndex]>, ParaId[]][]): S
|
||||
}));
|
||||
}
|
||||
|
||||
export default function useProposals (): Proposals | undefined {
|
||||
function useProposalsImpl (): Proposals | undefined {
|
||||
const { api } = useApi();
|
||||
const mountedRef = useIsMountedRef();
|
||||
const trigger = useEventTrigger([api.events.proposeParachain?.ProposeParachain]);
|
||||
@ -53,3 +53,7 @@ export default function useProposals (): Proposals | undefined {
|
||||
[approvedIds, mountedRef, proposalIds, sessionIndex, scheduled]
|
||||
);
|
||||
}
|
||||
|
||||
export default function useProposals (): Proposals | undefined {
|
||||
return useNamedHook('useProposals', useProposalsImpl);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import type { Option, StorageKey } from '@polkadot/types';
|
||||
import type { ParaId } from '@polkadot/types/interfaces';
|
||||
import type { PolkadotRuntimeParachainsParasParaLifecycle } from '@polkadot/types/lookup';
|
||||
|
||||
import { useApi, useEventTrigger, useMapEntries } from '@polkadot/react-hooks';
|
||||
import { useApi, useEventTrigger, useMapEntries, useNamedHook } from '@polkadot/react-hooks';
|
||||
|
||||
function extractIds (entries: [StorageKey<[ParaId]>, Option<PolkadotRuntimeParachainsParasParaLifecycle>][]): ParaId[] {
|
||||
return entries
|
||||
@ -25,7 +25,7 @@ function extractIds (entries: [StorageKey<[ParaId]>, Option<PolkadotRuntimeParac
|
||||
.sort((a, b) => a.cmp(b));
|
||||
}
|
||||
|
||||
export default function useUpomingIds (): ParaId[] | undefined {
|
||||
function useUpomingIdsImpl (): ParaId[] | undefined {
|
||||
const { api } = useApi();
|
||||
const trigger = useEventTrigger([
|
||||
api.events.session.NewSession,
|
||||
@ -37,3 +37,7 @@ export default function useUpomingIds (): ParaId[] | undefined {
|
||||
transform: extractIds
|
||||
});
|
||||
}
|
||||
|
||||
export default function useUpomingIds (): ParaId[] | undefined {
|
||||
return useNamedHook('useUpomingIds', useUpomingIdsImpl);
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import type { AuctionInfo, WinnerData, Winning } from './types';
|
||||
import BN from 'bn.js';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useApi, useBestNumber, useCall, useEventTrigger, useIsMountedRef } from '@polkadot/react-hooks';
|
||||
import { useApi, useBestNumber, useCall, useEventTrigger, useIsMountedRef, useNamedHook } from '@polkadot/react-hooks';
|
||||
import { BN_ONE, BN_ZERO, u8aEq } from '@polkadot/util';
|
||||
|
||||
import { CROWD_PREFIX } from './constants';
|
||||
@ -121,7 +121,7 @@ function mergeFirst (ranges: [number, number][], auctionInfo: AuctionInfo, prev:
|
||||
return prev;
|
||||
}
|
||||
|
||||
export default function useWinningData (auctionInfo?: AuctionInfo): Winning[] | undefined {
|
||||
function useWinningDataImpl (auctionInfo?: AuctionInfo): Winning[] | undefined {
|
||||
const { api } = useApi();
|
||||
const mountedRef = useIsMountedRef();
|
||||
const ranges = useLeaseRanges();
|
||||
@ -168,3 +168,7 @@ export default function useWinningData (auctionInfo?: AuctionInfo): Winning[] |
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function useWinningData (auctionInfo?: AuctionInfo): Winning[] | undefined {
|
||||
return useNamedHook('useWinningData', useWinningDataImpl, auctionInfo);
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ class ErrorBoundary extends React.Component<Props> {
|
||||
return displayError
|
||||
? (
|
||||
<article className='error extraMargin'>
|
||||
{t<string>('Uncaught error. Something went wrong with the query and rendering of this component. {{message}}', {
|
||||
replace: { message: displayError.message }
|
||||
})}
|
||||
<p>{t<string>('Uncaught error. Something went wrong with the query and rendering of this component. Please supply all the details below when logging an issue, it may help in tracing the cause.')}</p>
|
||||
<p>{displayError.message}</p>
|
||||
<p>{displayError.stack}</p>
|
||||
</article>
|
||||
)
|
||||
: children;
|
||||
|
||||
@ -34,6 +34,7 @@ export { useLoadingDelay } from './useLoadingDelay';
|
||||
export { useMapEntries } from './useMapEntries';
|
||||
export { useMapKeys } from './useMapKeys';
|
||||
export { useModal } from './useModal';
|
||||
export { useNamedHook } from './useNamedHook';
|
||||
export { useNonEmptyString } from './useNonEmptyString';
|
||||
export { useNonZeroBn } from './useNonZeroBn';
|
||||
export { useOwnEraRewards } from './useOwnEraRewards';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2021 @polkadot/react-hooks authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { RpcPromiseResult } from '@polkadot/api/types';
|
||||
import type { PromiseResult, QueryableStorageEntry } from '@polkadot/api/types';
|
||||
import type { StorageEntryTypeLatest } from '@polkadot/types/interfaces';
|
||||
import type { AnyFunction, Codec } from '@polkadot/types/types';
|
||||
import type { CallOptions, CallParam, CallParams } from './types';
|
||||
@ -34,10 +34,16 @@ interface QueryMapFn extends QueryTrackFn {
|
||||
};
|
||||
}
|
||||
|
||||
export type TrackFn = RpcPromiseResult<AnyFunction> | QueryTrackFn;
|
||||
type QueryFn =
|
||||
QueryableStorageEntry<'promise', []> |
|
||||
QueryableStorageEntry<'promise', []>['entries'] |
|
||||
QueryableStorageEntry<'promise', []>['keys'] |
|
||||
QueryableStorageEntry<'promise', []>['multi'];
|
||||
|
||||
type CallFn = (...params: unknown[]) => Promise<VoidFn>;
|
||||
|
||||
export type TrackFn = PromiseResult<AnyFunction> | QueryFn;
|
||||
|
||||
export interface Tracker {
|
||||
isActive: boolean;
|
||||
serialized: string | null;
|
||||
@ -77,6 +83,10 @@ export function unsubscribe (tracker: TrackerRef): void {
|
||||
}
|
||||
}
|
||||
|
||||
function isQuery (fn: TrackFn): fn is QueryableStorageEntry<'promise', []> {
|
||||
return !isUndefined((fn as QueryableStorageEntry<'promise', []>).creator);
|
||||
}
|
||||
|
||||
// subscribe, trying to play nice with the browser threads
|
||||
function subscribe <T> (mountedRef: MountedRef, tracker: TrackerRef, fn: TrackFn | undefined, params: CallParams, setValue: (value: any) => void, { transform = transformIdentity, withParams, withParamsTransform }: CallOptions<T> = {}): void {
|
||||
const validParams = params.filter((p) => !isUndefined(p));
|
||||
@ -97,13 +107,23 @@ function subscribe <T> (mountedRef: MountedRef, tracker: TrackerRef, fn: TrackFn
|
||||
tracker.current.subscriber = (fn as CallFn)(...params, (value: Codec): void => {
|
||||
// we use the isActive flag here since .subscriber may not be set on immediate callback)
|
||||
if (mountedRef.current && tracker.current.isActive) {
|
||||
mountedRef.current && tracker.current.isActive && setValue(
|
||||
withParams
|
||||
? [params, transform(value)]
|
||||
: withParamsTransform
|
||||
? transform([params, value])
|
||||
: transform(value)
|
||||
);
|
||||
try {
|
||||
setValue(
|
||||
withParams
|
||||
? [params, transform(value)]
|
||||
: withParamsTransform
|
||||
? transform([params, value])
|
||||
: transform(value)
|
||||
);
|
||||
} catch (error) {
|
||||
let extra = '...';
|
||||
|
||||
if (isQuery(fn)) {
|
||||
extra = `${fn.creator.section}.${fn.creator.method}`;
|
||||
}
|
||||
|
||||
throw new Error(`useCall(${extra}):: ${(error as Error).message}:: ${(error as Error).stack || '<unknown>'}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -39,11 +39,21 @@ function subscribe <T> (api: ApiPromise, mountedRef: MountedRef, tracker: Tracke
|
||||
if (mountedRef.current && tracker.current.isActive) {
|
||||
let valueIndex = -1;
|
||||
|
||||
mountedRef.current && tracker.current.isActive && setValue(
|
||||
transform(
|
||||
calls.map((_, index) => included[index] ? value[++valueIndex] : undefined)
|
||||
)
|
||||
);
|
||||
if (mountedRef.current && tracker.current.isActive) {
|
||||
try {
|
||||
setValue(
|
||||
transform(
|
||||
calls.map((_, index) =>
|
||||
included[index]
|
||||
? value[++valueIndex]
|
||||
: undefined
|
||||
)
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
throw new Error(`useCallMulti(...):: ${(error as Error).message}:: ${(error as Error).stack || '<unknown>'}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
10
packages/react-hooks/src/useNamedHook.ts
Normal file
10
packages/react-hooks/src/useNamedHook.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2017-2021 @polkadot/react-hooks authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export function useNamedHook <T> (name: string, fn: (...args: any[]) => T, ...args: unknown[]): T {
|
||||
try {
|
||||
return fn(...args);
|
||||
} catch (error) {
|
||||
throw new Error(`${name}:: ${(error as Error).message}:: ${(error as Error).stack || '<unknown>'}`);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user