Add error stakcs to useCall & ErrorBoundary (#6447)

This commit is contained in:
Jaco 2021-10-30 09:41:24 +02:00 committed by GitHub
parent 5958a96a26
commit 60a5334ff2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 137 additions and 42 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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';

View File

@ -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 {

View File

@ -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 {

View 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>'}`);
}
}