useAccounts hook (#1898)
* useAccounts hook * Drop some withRouter * Add setImmediate to trackStream * Combine unsubscribe into subscribe * Use before define * Ass trackPromise * Cleanup mapping for params * Addressbook display
This commit is contained in:
parent
ce141a4b4c
commit
e0acd15b43
@ -3,13 +3,12 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { getLedger, isLedger, withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { getLedger, isLedger } from '@polkadot/react-api';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
import { Button, CardGrid } from '@polkadot/react-components';
|
||||
|
||||
import CreateModal from './modals/Create';
|
||||
@ -20,7 +19,6 @@ import Banner from './Banner';
|
||||
import translate from './translate';
|
||||
|
||||
interface Props extends ComponentProps, I18nProps {
|
||||
accounts?: SubjectInfo[];
|
||||
}
|
||||
|
||||
// query the ledger for the address, adding it to the keyring
|
||||
@ -36,11 +34,12 @@ async function queryLedger (): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
function Overview ({ accounts, onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
function Overview ({ onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const [isCreateOpen, setIsCreateOpen] = useState(false);
|
||||
const [isImportOpen, setIsImportOpen] = useState(false);
|
||||
const [isQrOpen, setIsQrOpen] = useState(false);
|
||||
const emptyScreen = !(isCreateOpen || isImportOpen || isQrOpen) && accounts && (Object.keys(accounts).length === 0);
|
||||
const emptyScreen = !(isCreateOpen || isImportOpen || isQrOpen) && !hasAccounts;
|
||||
|
||||
const _toggleCreate = (): void => setIsCreateOpen(!isCreateOpen);
|
||||
const _toggleImport = (): void => setIsImportOpen(!isImportOpen);
|
||||
@ -105,7 +104,7 @@ function Overview ({ accounts, onStatusChange, t }: Props): React.ReactElement<P
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
{accounts && Object.keys(accounts).map((address): React.ReactNode => (
|
||||
{allAccounts.map((address): React.ReactNode => (
|
||||
<Account
|
||||
address={address}
|
||||
key={address}
|
||||
@ -115,8 +114,4 @@ function Overview ({ accounts, onStatusChange, t }: Props): React.ReactElement<P
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Overview,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'accounts' })
|
||||
);
|
||||
export default translate(Overview);
|
||||
|
||||
@ -3,14 +3,12 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { ComponentProps, LocationProps } from './types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
import { HelpOverlay, Tabs } from '@polkadot/react-components';
|
||||
import { withMulti, withObservable } from '@polkadot/react-api';
|
||||
|
||||
import basicMd from './md/basic.md';
|
||||
import Overview from './Overview';
|
||||
@ -18,34 +16,26 @@ import translate from './translate';
|
||||
import Vanity from './Vanity';
|
||||
|
||||
interface Props extends AppProps, I18nProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
location: any;
|
||||
}
|
||||
|
||||
function AccountsApp ({ allAccounts = {}, basePath, location, onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
function AccountsApp ({ basePath, onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
const { hasAccounts } = useAccounts();
|
||||
const [hidden, setHidden] = useState<string[]>(['vanity']);
|
||||
|
||||
useEffect((): void => {
|
||||
setHidden(
|
||||
Object.keys(allAccounts).length !== 0
|
||||
hasAccounts
|
||||
? []
|
||||
: ['vanity']
|
||||
);
|
||||
}, [allAccounts]);
|
||||
}, [hasAccounts]);
|
||||
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>): (props: LocationProps) => React.ReactNode => {
|
||||
// eslint-disable-next-line react/display-name
|
||||
return ({ match }: LocationProps): React.ReactNode => {
|
||||
return (
|
||||
<Component
|
||||
basePath={basePath}
|
||||
location={location}
|
||||
match={match}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>): React.ReactNode => (
|
||||
<Component
|
||||
basePath={basePath}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<main className='accounts--App'>
|
||||
@ -68,15 +58,11 @@ function AccountsApp ({ allAccounts = {}, basePath, location, onStatusChange, t
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/vanity`} render={_renderComponent(Vanity)} />
|
||||
<Route render={_renderComponent(Overview)} />
|
||||
<Route path={`${basePath}/vanity`}>{_renderComponent(Vanity)}</Route>
|
||||
<Route>{_renderComponent(Overview)}</Route>
|
||||
</Switch>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
AccountsApp,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
export default translate(AccountsApp);
|
||||
|
||||
@ -7,13 +7,6 @@ import { ActionStatus } from '@polkadot/react-components/Status/types';
|
||||
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
export interface LocationProps {
|
||||
location: any;
|
||||
match: {
|
||||
params: Record<string, string>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface BareProps {
|
||||
className?: string;
|
||||
style?: Record<string, any>;
|
||||
@ -21,7 +14,7 @@ export interface BareProps {
|
||||
|
||||
export type I18nProps = BareProps & WithTranslation;
|
||||
|
||||
export type ComponentProps = AppProps & LocationProps;
|
||||
export type ComponentProps = AppProps;
|
||||
|
||||
export interface ModalProps {
|
||||
onClose: () => void;
|
||||
|
||||
@ -3,25 +3,23 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Button, CardGrid } from '@polkadot/react-components';
|
||||
import addressObservable from '@polkadot/ui-keyring/observable/addresses';
|
||||
import { withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { useAddresses } from '@polkadot/react-hooks';
|
||||
|
||||
import CreateModal from './modals/Create';
|
||||
import Address from './Address';
|
||||
import translate from './translate';
|
||||
|
||||
interface Props extends ComponentProps, I18nProps {
|
||||
addresses?: SubjectInfo[];
|
||||
}
|
||||
|
||||
function Overview ({ addresses, onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
function Overview ({ onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
const { hasAddresses, allAddresses } = useAddresses();
|
||||
const [isCreateOpen, setIsCreateOpen] = useState(false);
|
||||
const emptyScreen = !isCreateOpen && (!addresses || Object.keys(addresses).length === 0);
|
||||
const emptyScreen = !isCreateOpen && !hasAddresses;
|
||||
|
||||
const _toggleCreate = (): void => setIsCreateOpen(!isCreateOpen);
|
||||
|
||||
@ -46,7 +44,7 @@ function Overview ({ addresses, onStatusChange, t }: Props): React.ReactElement<
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
{addresses && Object.keys(addresses).map((address): React.ReactNode => (
|
||||
{allAddresses.map((address): React.ReactNode => (
|
||||
<Address
|
||||
address={address}
|
||||
key={address}
|
||||
@ -56,8 +54,4 @@ function Overview ({ addresses, onStatusChange, t }: Props): React.ReactElement<
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Overview,
|
||||
translate,
|
||||
withObservable(addressObservable.subject, { propName: 'addresses' })
|
||||
);
|
||||
export default translate(Overview);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
@ -21,16 +20,6 @@ interface Props extends AppProps, I18nProps {
|
||||
}
|
||||
|
||||
function AddressBookApp ({ basePath, onStatusChange, t }: Props): React.ReactElement<Props> {
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>): () => React.ReactNode => {
|
||||
// eslint-disable-next-line react/display-name
|
||||
return (): React.ReactNode =>
|
||||
<Component
|
||||
basePath={basePath}
|
||||
location={location}
|
||||
onStatusChange={onStatusChange}
|
||||
/>;
|
||||
};
|
||||
|
||||
return (
|
||||
<main className='address-book--App'>
|
||||
<HelpOverlay md={basicMd} />
|
||||
@ -47,7 +36,13 @@ function AddressBookApp ({ basePath, onStatusChange, t }: Props): React.ReactEle
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route render={_renderComponent(Overview)} />
|
||||
<Route>
|
||||
<Overview
|
||||
basePath={basePath}
|
||||
location={location}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</main>
|
||||
);
|
||||
|
||||
@ -4,26 +4,23 @@
|
||||
|
||||
import { AccountId } from '@polkadot/types/interfaces';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useState } from 'react';
|
||||
import { Button, InputAddress, Modal, TxButton } from '@polkadot/react-components';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends I18nProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
depositors: AccountId[];
|
||||
proposalId: BN | number;
|
||||
}
|
||||
|
||||
function Seconding ({ allAccounts, depositors, proposalId, t }: Props): React.ReactElement<Props> | null {
|
||||
function Seconding ({ depositors, proposalId, t }: Props): React.ReactElement<Props> | null {
|
||||
const { hasAccounts } = useAccounts();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [isSecondingOpen, setIsSecondingOpen] = useState(false);
|
||||
const hasAccounts = allAccounts && Object.keys(allAccounts).length !== 0;
|
||||
|
||||
if (!hasAccounts) {
|
||||
return null;
|
||||
@ -85,8 +82,4 @@ function Seconding ({ allAccounts, depositors, proposalId, t }: Props): React.Re
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Seconding,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
export default translate(Seconding);
|
||||
|
||||
@ -3,26 +3,23 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useState } from 'react';
|
||||
import { Button, Dropdown, InputAddress, Modal, TxButton } from '@polkadot/react-components';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends I18nProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
referendumId: BN | number;
|
||||
}
|
||||
|
||||
function Voting ({ allAccounts, referendumId, t }: Props): React.ReactElement<Props> | null {
|
||||
function Voting ({ referendumId, t }: Props): React.ReactElement<Props> | null {
|
||||
const { hasAccounts } = useAccounts();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [isVotingOpen, setIsVotingOpen] = useState(false);
|
||||
const [voteValue, setVoteValue] = useState(true);
|
||||
const hasAccounts = allAccounts && Object.keys(allAccounts).length !== 0;
|
||||
|
||||
if (!hasAccounts) {
|
||||
return null;
|
||||
@ -93,8 +90,4 @@ function Voting ({ allAccounts, referendumId, t }: Props): React.ReactElement<Pr
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Voting,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
export default translate(Voting);
|
||||
|
||||
@ -7,8 +7,8 @@ import { BlockNumber } from '@polkadot/types/interfaces';
|
||||
import { BareProps } from '@polkadot/react-components/types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { withCalls, withMulti } from '@polkadot/react-api';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { withCalls } from '@polkadot/react-api';
|
||||
import { isHex } from '@polkadot/util';
|
||||
|
||||
import Query from '../Query';
|
||||
@ -17,15 +17,11 @@ import BlockByNumber from './ByNumber';
|
||||
|
||||
interface Props extends BareProps {
|
||||
chain_bestNumber?: BlockNumber;
|
||||
match: {
|
||||
params: {
|
||||
value: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function Entry ({ chain_bestNumber, match: { params: { value } } }: Props): React.ReactElement<Props> | null {
|
||||
const [stateValue, setStateValue] = useState<string>(value);
|
||||
function Entry ({ chain_bestNumber }: Props): React.ReactElement<Props> | null {
|
||||
const { value } = useParams();
|
||||
const [stateValue, setStateValue] = useState<string | undefined>(value);
|
||||
|
||||
useEffect((): void => {
|
||||
if (value && value !== stateValue) {
|
||||
@ -54,7 +50,4 @@ function Entry ({ chain_bestNumber, match: { params: { value } } }: Props): Reac
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
withRouter(Entry),
|
||||
withCalls<Props>('derive.chain.bestNumber')
|
||||
);
|
||||
export default withCalls<Props>('derive.chain.bestNumber')(Entry);
|
||||
|
||||
@ -8,7 +8,7 @@ import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { Log, LogType, Snippet } from './types';
|
||||
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import { withRouter, RouteComponentProps } from 'react-router';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { Transition } from 'semantic-ui-react';
|
||||
import snappy from 'snappyjs';
|
||||
import styled from 'styled-components';
|
||||
@ -41,17 +41,7 @@ interface Injected {
|
||||
window: null;
|
||||
}
|
||||
|
||||
interface Props extends AppProps, I18nProps, RouteComponentProps<{}> {
|
||||
match: {
|
||||
isExact: boolean;
|
||||
params: {
|
||||
base64?: string;
|
||||
};
|
||||
path: string;
|
||||
url: string;
|
||||
};
|
||||
// FIXME wait for proper eslint integration in tslint, then hopefully remove this
|
||||
history: any;
|
||||
interface Props extends AppProps, I18nProps {
|
||||
}
|
||||
|
||||
const snippets: Snippet[] = JSON.parse(JSON.stringify(allSnippets));
|
||||
@ -89,8 +79,10 @@ function decodeBase64 (base64: string): Snippet {
|
||||
}
|
||||
|
||||
// FIXME This... ladies & gentlemen, is a mess that should be untangled
|
||||
function Playground ({ className, history, match: { params: { base64 } }, t }: Props): React.ReactElement<Props> {
|
||||
function Playground ({ className, t }: Props): React.ReactElement<Props> {
|
||||
const { api, isDevelopment } = useApiContext();
|
||||
const history = useHistory();
|
||||
const { base64 } = useParams();
|
||||
const injectedRef = useRef<Injected | null>(null);
|
||||
const [code, setCode] = useState('');
|
||||
const [isAnimated, setIsAnimated] = useState(true);
|
||||
@ -334,10 +326,8 @@ function Playground ({ className, history, match: { params: { base64 } }, t }: P
|
||||
);
|
||||
}
|
||||
|
||||
const Routed = withRouter(Playground);
|
||||
|
||||
export default translate(
|
||||
styled(Routed)`
|
||||
styled(Playground)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
|
||||
@ -2,17 +2,15 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types';
|
||||
import { AccountId, StakingLedger } from '@polkadot/types/interfaces';
|
||||
import { ComponentProps } from '../types';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { withCalls, withMulti } from '@polkadot/react-api/with';
|
||||
import { Button, CardGrid } from '@polkadot/react-components';
|
||||
import { trackStream, useApiContext } from '@polkadot/react-hooks';
|
||||
import { AccountName } from '@polkadot/react-query';
|
||||
import { Option } from '@polkadot/types';
|
||||
import createOption from '@polkadot/ui-keyring/options/item';
|
||||
@ -21,12 +19,10 @@ import Account from './Account';
|
||||
import StartStaking from './NewStake';
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends I18nProps, ComponentProps, ApiProps {
|
||||
queryBonded?: Option<AccountId>[];
|
||||
queryLedger?: Option<StakingLedger>[];
|
||||
interface Props extends I18nProps, ComponentProps {
|
||||
}
|
||||
|
||||
function getMyStashes (queryBonded?: Option<AccountId>[], queryLedger?: Option<StakingLedger>[], allAccounts?: SubjectInfo): string[] | null {
|
||||
function getMyStashes (allAccounts: string[], queryBonded?: Option<AccountId>[], queryLedger?: Option<StakingLedger>[]): string[] | null {
|
||||
const result: string[] = [];
|
||||
|
||||
if (!queryBonded || !queryLedger) {
|
||||
@ -34,7 +30,7 @@ function getMyStashes (queryBonded?: Option<AccountId>[], queryLedger?: Option<S
|
||||
}
|
||||
|
||||
queryBonded.forEach((value, index): void => {
|
||||
value.isSome && allAccounts && result.push(Object.keys(allAccounts)[index]);
|
||||
value.isSome && result.push(allAccounts[index]);
|
||||
});
|
||||
|
||||
queryLedger.forEach((ledger): void => {
|
||||
@ -48,9 +44,12 @@ function getMyStashes (queryBonded?: Option<AccountId>[], queryLedger?: Option<S
|
||||
return result;
|
||||
}
|
||||
|
||||
function Accounts ({ allAccounts, allStashes, className, queryBonded, queryLedger, recentlyOnline, t }: Props): React.ReactElement<Props> {
|
||||
function Accounts ({ allAccounts, allStashes, className, recentlyOnline, t }: Props): React.ReactElement<Props> {
|
||||
const { api } = useApiContext();
|
||||
const queryBonded = trackStream<Option<AccountId>[]>(api.query.staking.bonded.multi as any, [allAccounts]);
|
||||
const queryLedger = trackStream<Option<StakingLedger>[]>(api.query.staking.ledger.multi as any, [allAccounts]);
|
||||
const [isNewStakeOpen, setIsNewStateOpen] = useState(false);
|
||||
const foundStashes = getMyStashes(queryBonded, queryLedger, allAccounts);
|
||||
const foundStashes = getMyStashes(allAccounts, queryBonded, queryLedger);
|
||||
const stashOptions = allStashes.map((stashId): KeyringSectionOption =>
|
||||
createOption(stashId, (<AccountName params={stashId} />) as any)
|
||||
);
|
||||
@ -91,25 +90,10 @@ function Accounts ({ allAccounts, allStashes, className, queryBonded, queryLedge
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
export default translate(
|
||||
styled(Accounts)`
|
||||
.ui--CardGrid-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
`,
|
||||
translate,
|
||||
withCalls<Props>(
|
||||
['query.staking.bonded', {
|
||||
isMulti: true,
|
||||
propName: 'queryBonded',
|
||||
paramPick: ({ allAccounts }: Props): undefined | string[] =>
|
||||
allAccounts && Object.keys(allAccounts)
|
||||
}],
|
||||
['query.staking.ledger', {
|
||||
isMulti: true,
|
||||
propName: 'queryLedger',
|
||||
paramPick: ({ allAccounts }: Props): undefined | string[] =>
|
||||
allAccounts && Object.keys(allAccounts)
|
||||
}]
|
||||
)
|
||||
`
|
||||
);
|
||||
|
||||
@ -6,21 +6,13 @@ import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ComponentProps } from '../types';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Button, InputAddressSimple } from '@polkadot/react-components';
|
||||
|
||||
import translate from '../translate';
|
||||
import Validator from './Validator';
|
||||
|
||||
interface Props extends I18nProps, ComponentProps, RouteComponentProps<{}> {
|
||||
match: {
|
||||
isExact: boolean;
|
||||
params: {
|
||||
value: string;
|
||||
};
|
||||
path: string;
|
||||
url: string;
|
||||
};
|
||||
interface Props extends I18nProps, ComponentProps {
|
||||
}
|
||||
|
||||
// const _onQuery = (): void => {
|
||||
@ -46,7 +38,8 @@ interface Props extends I18nProps, ComponentProps, RouteComponentProps<{}> {
|
||||
// />
|
||||
// </Input>
|
||||
|
||||
function Query ({ className, sessionRewards, match: { params: { value } }, t }: Props): React.ReactElement<Props> {
|
||||
function Query ({ className, sessionRewards, t }: Props): React.ReactElement<Props> {
|
||||
const { value } = useParams();
|
||||
const [validatorId, setValidatorId] = useState<string | null>(value || null);
|
||||
|
||||
const _onQuery = (): void => {
|
||||
@ -81,4 +74,4 @@ function Query ({ className, sessionRewards, match: { params: { value } }, t }:
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(withRouter(Query));
|
||||
export default translate(Query);
|
||||
|
||||
@ -4,9 +4,7 @@
|
||||
|
||||
import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
|
||||
import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { AccountId, BlockNumber } from '@polkadot/types/interfaces';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
@ -16,9 +14,7 @@ import styled from 'styled-components';
|
||||
import { Option } from '@polkadot/types';
|
||||
import { HelpOverlay } from '@polkadot/react-components';
|
||||
import Tabs from '@polkadot/react-components/Tabs';
|
||||
import { withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { trackStream, useApiContext, useSessionRewards } from '@polkadot/react-hooks';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { trackStream, useAccounts, useApiContext, useSessionRewards } from '@polkadot/react-hooks';
|
||||
|
||||
import Accounts from './Actions/Accounts';
|
||||
import basicMd from './md/basic.md';
|
||||
@ -27,8 +23,7 @@ import Query from './Query';
|
||||
import { MAX_SESSIONS } from './constants';
|
||||
import translate from './translate';
|
||||
|
||||
interface Props extends AppProps, ApiProps, I18nProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
interface Props extends AppProps, I18nProps {
|
||||
}
|
||||
|
||||
const EMPY_ACCOUNTS: string[] = [];
|
||||
@ -43,8 +38,9 @@ function transformStakingControllers ([stashes, controllers]: [AccountId[], Opti
|
||||
];
|
||||
}
|
||||
|
||||
function App ({ allAccounts, basePath, className, t }: Props): React.ReactElement<Props> {
|
||||
function App ({ basePath, className, t }: Props): React.ReactElement<Props> {
|
||||
const { api } = useApiContext();
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const stakingControllers = trackStream<[string[], string[]]>(api.derive.staking.controllers, [], { transform: transformStakingControllers });
|
||||
const bestNumber = trackStream<BlockNumber>(api.derive.chain.bestNumber, []);
|
||||
const recentlyOnline = trackStream<DerivedHeartbeats>(api.derive.imOnline.receivedHeartbeats, []);
|
||||
@ -52,32 +48,22 @@ function App ({ allAccounts, basePath, className, t }: Props): React.ReactElemen
|
||||
const sessionRewards = useSessionRewards(MAX_SESSIONS);
|
||||
const routeMatch = useRouteMatch({ path: basePath, strict: true });
|
||||
|
||||
const hasAccounts = !!allAccounts && Object.keys(allAccounts).length !== 0;
|
||||
const hasQueries = hasAccounts && !!(api.query.imOnline?.authoredBlocks);
|
||||
const [allStashes, allControllers] = stakingControllers || EMPTY_ALL;
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>, className?: string): () => React.ReactNode => {
|
||||
// eslint-disable-next-line react/display-name
|
||||
return (): React.ReactNode => {
|
||||
if (!allAccounts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Component
|
||||
allAccounts={allAccounts}
|
||||
allControllers={allControllers}
|
||||
allStashes={allStashes}
|
||||
bestNumber={bestNumber}
|
||||
className={className}
|
||||
hasAccounts={hasAccounts}
|
||||
hasQueries={hasQueries}
|
||||
recentlyOnline={recentlyOnline}
|
||||
sessionRewards={sessionRewards}
|
||||
stakingOverview={stakingOverview}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>, className?: string): React.ReactNode => (
|
||||
<Component
|
||||
allAccounts={allAccounts}
|
||||
allControllers={allControllers}
|
||||
allStashes={allStashes}
|
||||
bestNumber={bestNumber}
|
||||
className={className}
|
||||
hasAccounts={hasAccounts}
|
||||
hasQueries={hasQueries}
|
||||
recentlyOnline={recentlyOnline}
|
||||
sessionRewards={sessionRewards}
|
||||
stakingOverview={stakingOverview}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<main className={`staking--App ${className}`}>
|
||||
@ -111,16 +97,16 @@ function App ({ allAccounts, basePath, className, t }: Props): React.ReactElemen
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/actions`} render={_renderComponent(Accounts)} />
|
||||
<Route path={`${basePath}/query/:value`} render={_renderComponent(Query)} />
|
||||
<Route path={`${basePath}/query`} render={_renderComponent(Query)} />
|
||||
<Route path={`${basePath}/actions`}>{_renderComponent(Accounts)}</Route>
|
||||
<Route path={`${basePath}/query/:value`}>{_renderComponent(Query)}</Route>
|
||||
<Route path={`${basePath}/query`}>{_renderComponent(Query)}</Route>
|
||||
</Switch>
|
||||
{_renderComponent(Overview, routeMatch?.isExact ? '' : 'staking--hidden')()}
|
||||
{_renderComponent(Overview, routeMatch?.isExact ? '' : 'staking--hidden')}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
export default translate(
|
||||
styled(App)`
|
||||
.staking--hidden {
|
||||
display: none;
|
||||
@ -137,7 +123,5 @@ export default withMulti(
|
||||
.staking--Chart+.staking--Chart {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
`,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
`
|
||||
);
|
||||
|
||||
@ -5,12 +5,11 @@
|
||||
import { DerivedFees, DerivedBalances, DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
|
||||
import { BlockNumber } from '@polkadot/types/interfaces';
|
||||
import { SessionRewards } from '@polkadot/react-hooks/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
export type Nominators = Record<string, string[]>;
|
||||
|
||||
export interface ComponentProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
allAccounts: string[];
|
||||
allControllers: string[];
|
||||
allStashes: string[];
|
||||
bestNumber?: BlockNumber;
|
||||
|
||||
@ -23,10 +23,9 @@ function SetKey ({ allAccounts, className, isMine, sudoKey, t }: Props): React.R
|
||||
}, [selected, sudoKey]);
|
||||
|
||||
const willLose = isMine &&
|
||||
!!Object.keys(allAccounts).length &&
|
||||
!!selected &&
|
||||
selected !== sudoKey &&
|
||||
!Object.keys(allAccounts).find((s): boolean => s === selected);
|
||||
allAccounts.some((s): boolean => s === selected);
|
||||
|
||||
return (
|
||||
<section>
|
||||
|
||||
@ -4,14 +4,12 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import { Icon, Tabs } from '@polkadot/react-components';
|
||||
import { withCalls, withMulti, withObservable } from '@polkadot/react-api';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { trackStream, useAccounts, useApiContext } from '@polkadot/react-hooks';
|
||||
|
||||
import SetKey from './SetKey';
|
||||
import Sudo from './Sudo';
|
||||
@ -19,17 +17,16 @@ import Sudo from './Sudo';
|
||||
import translate from './translate';
|
||||
|
||||
interface Props extends AppProps, I18nProps {
|
||||
allAccounts: SubjectInfo;
|
||||
sudoKey?: string;
|
||||
}
|
||||
|
||||
function App ({ allAccounts, basePath, sudoKey, t }: Props): React.ReactElement<Props> {
|
||||
function App ({ basePath, t }: Props): React.ReactElement<Props> {
|
||||
const { api } = useApiContext();
|
||||
const sudoKey = trackStream<string>(api.query.sudo.key, [], { transform: (k): string => k.toString() });
|
||||
const { allAccounts } = useAccounts();
|
||||
const [isMine, setIsMine] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
setIsMine(
|
||||
!!sudoKey && !!allAccounts && Object.keys(allAccounts).some((key): boolean => key === sudoKey)
|
||||
);
|
||||
setIsMine(!!sudoKey && allAccounts.some((key): boolean => key === sudoKey));
|
||||
}, [allAccounts, sudoKey]);
|
||||
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>): () => React.ReactNode => {
|
||||
@ -83,15 +80,4 @@ function App ({ allAccounts, basePath, sudoKey, t }: Props): React.ReactElement<
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
App,
|
||||
translate,
|
||||
withCalls<Props>(
|
||||
['query.sudo.key', {
|
||||
propName: 'sudoKey',
|
||||
transform: (key): string =>
|
||||
key.toString()
|
||||
}]
|
||||
),
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
export default translate(App);
|
||||
|
||||
@ -2,10 +2,8 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
export interface ComponentProps {
|
||||
allAccounts: SubjectInfo;
|
||||
allAccounts: string[];
|
||||
isMine: boolean;
|
||||
sudoKey?: string;
|
||||
}
|
||||
|
||||
@ -3,13 +3,11 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import Tabs from '@polkadot/react-components/Tabs';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
|
||||
import Hash from './Hash';
|
||||
import Rpc from './Rpc';
|
||||
@ -18,11 +16,10 @@ import Verify from './Verify';
|
||||
import translate from './translate';
|
||||
|
||||
interface Props extends AppProps, I18nProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
}
|
||||
|
||||
function ToolboxApp ({ allAccounts, basePath, t }: Props): React.ReactElement<Props> {
|
||||
const hasAccounts = allAccounts && Object.keys(allAccounts).length !== 0;
|
||||
function ToolboxApp ({ basePath, t }: Props): React.ReactElement<Props> {
|
||||
const { hasAccounts } = useAccounts();
|
||||
const tabs = [
|
||||
{
|
||||
isRoot: true,
|
||||
@ -64,8 +61,4 @@ function ToolboxApp ({ allAccounts, basePath, t }: Props): React.ReactElement<Pr
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
ToolboxApp,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
export default translate(ToolboxApp);
|
||||
|
||||
@ -4,14 +4,13 @@
|
||||
|
||||
import { TreasuryProposal as TreasuryProposalType } from '@polkadot/types/interfaces';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Option } from '@polkadot/types';
|
||||
import { ActionItem, Icon, TreasuryProposal } from '@polkadot/react-components';
|
||||
import { withCalls, withMulti, withObservable } from '@polkadot/react-api';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import { withCalls, withMulti } from '@polkadot/react-api';
|
||||
import { useAccounts } from '@polkadot/react-hooks';
|
||||
|
||||
import translate from '../translate';
|
||||
import Approve from './Approve';
|
||||
@ -22,7 +21,6 @@ const Approved = styled.h3`
|
||||
`;
|
||||
|
||||
interface Props extends I18nProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
isApproved: boolean;
|
||||
proposal?: TreasuryProposalType | null;
|
||||
proposalId: string;
|
||||
@ -30,7 +28,9 @@ interface Props extends I18nProps {
|
||||
onRespond: () => void;
|
||||
}
|
||||
|
||||
function ProposalDisplay ({ allAccounts, isApproved, onPopulate, onRespond, proposal, proposalId, t }: Props): React.ReactElement<Props> | null {
|
||||
function ProposalDisplay ({ isApproved, onPopulate, onRespond, proposal, proposalId, t }: Props): React.ReactElement<Props> | null {
|
||||
const { hasAccounts } = useAccounts();
|
||||
|
||||
useEffect((): void => {
|
||||
onPopulate();
|
||||
}, [proposal]);
|
||||
@ -39,8 +39,6 @@ function ProposalDisplay ({ allAccounts, isApproved, onPopulate, onRespond, prop
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasAccounts = allAccounts && Object.keys(allAccounts).length !== 0;
|
||||
|
||||
return (
|
||||
<ActionItem
|
||||
accessory={
|
||||
@ -87,6 +85,5 @@ export default withMulti(
|
||||
transform: (value: Option<TreasuryProposalType>): TreasuryProposalType | null =>
|
||||
value.unwrapOr(null)
|
||||
}]
|
||||
),
|
||||
withObservable(keyring.accounts.subject, { propName: 'allAccounts' })
|
||||
)
|
||||
);
|
||||
|
||||
@ -8,21 +8,21 @@ import { I18nProps } from '@polkadot/react-components/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { withCalls, withMulti } from '@polkadot/react-api';
|
||||
import { Column } from '@polkadot/react-components';
|
||||
|
||||
import Proposal from './Proposal';
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends I18nProps, RouteComponentProps<{}> {
|
||||
interface Props extends I18nProps {
|
||||
isApprovals?: boolean;
|
||||
treasury_approvals?: BN[];
|
||||
treasury_proposalCount?: BN;
|
||||
}
|
||||
|
||||
function ProposalsBase ({ history, isApprovals = false, treasury_approvals, treasury_proposalCount, t }: Props): React.ReactElement<Props> {
|
||||
function ProposalsBase ({ isApprovals = false, treasury_approvals, treasury_proposalCount, t }: Props): React.ReactElement<Props> {
|
||||
const history = useHistory();
|
||||
const [isEmpty, setIsEmpty] = useState(true);
|
||||
const [proposalIndices, setProposalIndices] = useState<BN[]>([]);
|
||||
|
||||
@ -71,7 +71,7 @@ function ProposalsBase ({ history, isApprovals = false, treasury_approvals, trea
|
||||
}
|
||||
|
||||
const Proposals = withMulti(
|
||||
withRouter(ProposalsBase),
|
||||
ProposalsBase,
|
||||
translate,
|
||||
withCalls<Props>(
|
||||
['query.treasury.approvals', {
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { I18nProps as Props } from '@polkadot/react-components/types';
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import { withRouter, RouteComponentProps } from 'react-router';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import routing from '@polkadot/apps-routing';
|
||||
import { StatusContext } from '@polkadot/react-components';
|
||||
@ -15,8 +15,6 @@ import Status from './Status';
|
||||
import translate from '../translate';
|
||||
import NotFound from './NotFound';
|
||||
|
||||
interface Props extends I18nProps, RouteComponentProps {}
|
||||
|
||||
const unknown = {
|
||||
display: {
|
||||
needsApi: undefined
|
||||
@ -25,7 +23,8 @@ const unknown = {
|
||||
name: ''
|
||||
};
|
||||
|
||||
function Content ({ className, location, t }: Props): React.ReactElement<Props> {
|
||||
function Content ({ className, t }: Props): React.ReactElement<Props> {
|
||||
const location = useLocation();
|
||||
const { isApiConnected, isApiReady } = useApiContext();
|
||||
const { queueAction, stqueue, txqueue } = useContext(StatusContext);
|
||||
const app = location.pathname.slice(1) || '';
|
||||
@ -58,26 +57,24 @@ function Content ({ className, location, t }: Props): React.ReactElement<Props>
|
||||
|
||||
// React-router needs to be first, otherwise we have blocked updates
|
||||
export default translate(
|
||||
withRouter(
|
||||
styled(Content)`
|
||||
background: #fafafa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
padding: 0 2rem;
|
||||
styled(Content)`
|
||||
background: #fafafa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
padding: 0 2rem;
|
||||
|
||||
@media(max-width: 768px) {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
@media(max-width: 768px) {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.connecting {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
`
|
||||
)
|
||||
.connecting {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { Route } from '@polkadot/apps-routing/types';
|
||||
import { AccountId } from '@polkadot/types/interfaces';
|
||||
|
||||
@ -12,9 +11,8 @@ import React, { useEffect, useState } from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import { Icon, Menu, Tooltip } from '@polkadot/react-components';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withCalls, withMulti, withObservable } from '@polkadot/react-api';
|
||||
import { useApiContext } from '@polkadot/react-hooks';
|
||||
import { withCalls, withMulti } from '@polkadot/react-api';
|
||||
import { useAccounts, useApiContext } from '@polkadot/react-hooks';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
|
||||
import translate from '../translate';
|
||||
@ -22,7 +20,6 @@ import translate from '../translate';
|
||||
interface Props extends I18nProps {
|
||||
isCollapsed: boolean;
|
||||
onClick: () => void;
|
||||
allAccounts?: SubjectInfo;
|
||||
route: Route;
|
||||
sudoKey?: AccountId;
|
||||
}
|
||||
@ -77,18 +74,14 @@ function checkVisible (name: string, { api, isApiReady, isApiConnected }: ApiPro
|
||||
return notFound.length === 0;
|
||||
}
|
||||
|
||||
function Item ({ allAccounts, route: { Modal, display, i18n, icon, name }, t, isCollapsed, onClick, sudoKey }: Props): React.ReactElement<Props> | null {
|
||||
function Item ({ route: { Modal, display, i18n, icon, name }, t, isCollapsed, onClick, sudoKey }: Props): React.ReactElement<Props> | null {
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const apiProps = useApiContext();
|
||||
const [hasAccounts, setHasAccounts] = useState(false);
|
||||
const [hasSudo, setHasSudo] = useState(false);
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
setHasAccounts(Object.keys(allAccounts || {}).length !== 0);
|
||||
}, [allAccounts]);
|
||||
|
||||
useEffect((): void => {
|
||||
setHasSudo(!!sudoKey && Object.keys(allAccounts || {}).some((address): boolean => sudoKey.eq(address)));
|
||||
setHasSudo(!!sudoKey && allAccounts.some((address): boolean => sudoKey.eq(address)));
|
||||
}, [allAccounts, sudoKey]);
|
||||
|
||||
useEffect((): void => {
|
||||
@ -149,6 +142,5 @@ export default withMulti(
|
||||
translate,
|
||||
withCalls<Props>(
|
||||
['query.sudo.key', { propName: 'sudoKey' }]
|
||||
),
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
)
|
||||
);
|
||||
|
||||
@ -2,45 +2,27 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { I18nProps as Props } from '@polkadot/react-components/types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import { withApi, withMulti, withObservable } from '@polkadot/react-api';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { useAccounts, useApiContext } from '@polkadot/react-hooks';
|
||||
|
||||
import translate from '../translate';
|
||||
import BaseOverlay from './Base';
|
||||
|
||||
interface Props extends I18nProps, ApiProps {
|
||||
allAccounts?: SubjectInfo;
|
||||
}
|
||||
|
||||
function Accounts ({ allAccounts, isApiReady, className, t }: Props): React.ReactElement<Props> | null {
|
||||
const [hasAccounts, setHasAccounts] = useState(false);
|
||||
function Accounts ({ className, t }: Props): React.ReactElement<Props> | null {
|
||||
const { hasAccounts } = useAccounts();
|
||||
const { isApiReady } = useApiContext();
|
||||
const [isHidden, setIsHidden] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
if (!allAccounts) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newHas = Object.keys(allAccounts).length !== 0;
|
||||
|
||||
if (newHas !== hasAccounts) {
|
||||
setHasAccounts(newHas);
|
||||
}
|
||||
}, [allAccounts]);
|
||||
|
||||
const _onClose = (): void => setIsHidden(true);
|
||||
|
||||
if (!isApiReady || hasAccounts || isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _onClose = (): void => setIsHidden(true);
|
||||
|
||||
return (
|
||||
<BaseOverlay
|
||||
className={className}
|
||||
@ -59,13 +41,10 @@ function Accounts ({ allAccounts, isApiReady, className, t }: Props): React.Reac
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
export default translate(
|
||||
styled(Accounts)`
|
||||
background: #fff6cb;
|
||||
border-color: #e7c000;
|
||||
color: #6b5900;
|
||||
`,
|
||||
translate,
|
||||
withApi,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
`
|
||||
);
|
||||
|
||||
@ -6,15 +6,13 @@ import { Proposal } from '@polkadot/types/interfaces';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Card from './Card';
|
||||
import ProposedAction, { styles as proposedActionStyles } from './ProposedAction';
|
||||
import { styles as rowStyles } from './Row';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
interface Props {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
accessory?: React.ReactNode;
|
||||
@ -49,4 +47,4 @@ function ActionItem ({ className, children, accessory, idNumber, proposal, expan
|
||||
);
|
||||
}
|
||||
|
||||
export default withRouter(styled(ActionItem)`${styles}`);
|
||||
export default styled(ActionItem)`${styles}`;
|
||||
|
||||
@ -3,14 +3,13 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Icon from './Icon';
|
||||
import { classes } from './util';
|
||||
|
||||
export interface InsetProps extends RouteComponentProps {
|
||||
export interface InsetProps {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
isCollapsible?: boolean;
|
||||
@ -22,7 +21,8 @@ export interface InsetProps extends RouteComponentProps {
|
||||
withBottomMargin?: boolean;
|
||||
}
|
||||
|
||||
function Inset ({ children, className, header, history, href, isCollapsible, isError, isSuccess, withBottomMargin, withTopMargin }: InsetProps): React.ReactElement<InsetProps> | null {
|
||||
function Inset ({ children, className, header, href, isCollapsible, isError, isSuccess, withBottomMargin, withTopMargin }: InsetProps): React.ReactElement<InsetProps> | null {
|
||||
const history = useHistory();
|
||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||
|
||||
if (!children) {
|
||||
@ -71,84 +71,82 @@ function Inset ({ children, className, header, history, href, isCollapsible, isE
|
||||
);
|
||||
}
|
||||
|
||||
export default withRouter(
|
||||
styled(Inset)`
|
||||
& {
|
||||
box-shadow: 0 3px 3px rgba(0,0,0,.2);
|
||||
position: relative;
|
||||
background: #fefefe;
|
||||
padding: 1rem;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
export default styled(Inset)`
|
||||
& {
|
||||
box-shadow: 0 3px 3px rgba(0,0,0,.2);
|
||||
position: relative;
|
||||
background: #fefefe;
|
||||
padding: 1rem;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.bottom-margin {
|
||||
margin-bottom: 2rem;
|
||||
&.bottom-margin {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
&.top-margin {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: rgba(255, 0, 0, 0.05);
|
||||
|
||||
&, h1, h2, h3, h4, h5, h6, p {
|
||||
color: rgba(156, 0, 0) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.success {
|
||||
border: 1px solid rgb(168, 255, 136);
|
||||
background: rgba(0, 255, 0, 0.05);
|
||||
|
||||
&, h1, h2, h3, h4, h5, h6, p {
|
||||
color: rgba(34, 125, 0) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
cursor: pointer;
|
||||
height: 2rem;
|
||||
width: 100%;
|
||||
|
||||
h3 {
|
||||
line-height: 2rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.top-margin {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.icon {
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
font-size: 2rem;
|
||||
color: rgba(0,0,0,0.35);
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
line-height: 4rem;
|
||||
transition: all 0.2s;
|
||||
transform-origin: center center;
|
||||
|
||||
&.error {
|
||||
background: rgba(255, 0, 0, 0.05);
|
||||
|
||||
&, h1, h2, h3, h4, h5, h6, p {
|
||||
color: rgba(156, 0, 0) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.success {
|
||||
border: 1px solid rgb(168, 255, 136);
|
||||
background: rgba(0, 255, 0, 0.05);
|
||||
|
||||
&, h1, h2, h3, h4, h5, h6, p {
|
||||
color: rgba(34, 125, 0) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
cursor: pointer;
|
||||
height: 2rem;
|
||||
width: 100%;
|
||||
|
||||
h3 {
|
||||
line-height: 2rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
font-size: 2rem;
|
||||
color: rgba(0,0,0,0.35);
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
line-height: 4rem;
|
||||
transition: all 0.2s;
|
||||
transform-origin: center center;
|
||||
|
||||
&.collapsed {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.children {
|
||||
&.collapsed {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.as-link {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 5px 5px rgba(0,0,0,.2);
|
||||
transform: translateY(-2px);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
.children {
|
||||
&.collapsed {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.as-link {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 5px 5px rgba(0,0,0,.2);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -2,7 +2,10 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export { default as trackStream } from './trackStream';
|
||||
export { default as trackPromise } from './track/trackPromise';
|
||||
export { default as trackStream } from './track/trackStream';
|
||||
export { default as useAccounts } from './useAccounts';
|
||||
export { default as useAddresses } from './useAddresses';
|
||||
export { default as useApiContext } from './useApiContext';
|
||||
export { default as useDebounce } from './useDebounce';
|
||||
export { default as useFavorites } from './useFavorites';
|
||||
|
||||
58
packages/react-hooks/src/track/trackPromise.tsx
Normal file
58
packages/react-hooks/src/track/trackPromise.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2017-2019 @polkadot/react-hooks authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Options, Params } from './types';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { extractParams, transformIdentity } from './util';
|
||||
|
||||
interface TrackFn <T> {
|
||||
(a: any, b: any, c: any): Promise<T>;
|
||||
(a: any, b: any): Promise<T>;
|
||||
(a: any): Promise<T>;
|
||||
(): Promise<T>;
|
||||
}
|
||||
|
||||
// tracks a promise, typically an api.* call that
|
||||
// - returns a promise with the value
|
||||
// FIXME The typings here need some serious TLC
|
||||
export default function trackPromise <T> (fn: TrackFn<T> | undefined, params: any, { paramMap = transformIdentity, transform = transformIdentity }: Options<T> = {}): T | undefined {
|
||||
const [value, setValue] = useState<T | undefined>();
|
||||
const tracker = useRef<{ serialized: string | null }>({ serialized: null });
|
||||
|
||||
const _subscribe = (params: Params): void => {
|
||||
setImmediate((): void => {
|
||||
if (fn) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore We tried to get the typings right, close but no cigar...
|
||||
fn(...params).then((value: any): void => setValue(transform(value)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// initial round, subscribe once
|
||||
useEffect((): void => {
|
||||
const [serialized, mappedParams] = extractParams(params, paramMap);
|
||||
|
||||
tracker.current.serialized = serialized;
|
||||
|
||||
if (mappedParams) {
|
||||
_subscribe(mappedParams);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// on changes, re-get
|
||||
useEffect((): void => {
|
||||
const [serialized, mappedParams] = extractParams(params, paramMap);
|
||||
|
||||
if (mappedParams && serialized !== tracker.current.serialized) {
|
||||
tracker.current.serialized = serialized;
|
||||
|
||||
_subscribe(mappedParams);
|
||||
}
|
||||
}, [params]);
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -2,15 +2,11 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Options, Params } from './types';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { isNull, isUndefined } from '@polkadot/util';
|
||||
|
||||
type Params = [] | [any] | [any, any] | [any, any, any];
|
||||
|
||||
interface Options <T> {
|
||||
paramMap?: (params: any) => any;
|
||||
transform?: (value: any) => T;
|
||||
}
|
||||
import { dummyPromise, extractParams, transformIdentity } from './util';
|
||||
|
||||
interface TrackFnCallback <T> {
|
||||
(value: T): void;
|
||||
@ -25,41 +21,28 @@ interface TrackFn <T> {
|
||||
(cb: TrackFnCallback<T>): Promise<Unsub>;
|
||||
}
|
||||
|
||||
const dummySubscribe = Promise.resolve((): void => {
|
||||
// we do nothing, this is a noop
|
||||
});
|
||||
|
||||
function transformIdentity (value: any): any {
|
||||
return value;
|
||||
}
|
||||
|
||||
// extract the serialized and mapped params, all ready for use in our call
|
||||
function extractParams (params: any[], paramMap: (params: any[]) => any): [string, Params | null] {
|
||||
return [
|
||||
JSON.stringify({ a: params }),
|
||||
params.length === 0 || !params.some((param): boolean => isNull(param) || isUndefined(null))
|
||||
? paramMap(params)
|
||||
: null
|
||||
];
|
||||
}
|
||||
|
||||
// tracks a stream, typically an api.* call that
|
||||
// - returns a promise with an unsubscription
|
||||
// - has a callback to set the value
|
||||
// FIXME The typings here need some serious TLC
|
||||
export default function trackStream <T> (fn: TrackFn<any> | undefined, params: any, { paramMap = transformIdentity, transform = transformIdentity }: Options<T> = {}): T | undefined {
|
||||
const [value, setValue] = useState<T | undefined>();
|
||||
const tracker = useRef<{ serialized: string | null; subscriber: Promise<Unsub> }>({ serialized: null, subscriber: dummySubscribe });
|
||||
const tracker = useRef<{ serialized: string | null; subscriber: Promise<Unsub> }>({ serialized: null, subscriber: dummyPromise });
|
||||
|
||||
const _subscribe = (params: Params): void => {
|
||||
tracker.current.subscriber = fn
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore We tried to get the typings right, close but no cigar...
|
||||
? fn(...params, (value: any): T => setValue(transform(value)))
|
||||
: dummySubscribe;
|
||||
};
|
||||
const _unsubscribe = (): void => {
|
||||
tracker.current.subscriber.then((fn): void => fn());
|
||||
tracker.current.subscriber = dummyPromise;
|
||||
};
|
||||
const _subscribe = (params: Params): void => {
|
||||
_unsubscribe();
|
||||
|
||||
setImmediate((): void => {
|
||||
tracker.current.subscriber = fn
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore We tried to get the typings right, close but no cigar...
|
||||
? fn(...params, (value: any): void => setValue(transform(value)))
|
||||
: dummyPromise;
|
||||
});
|
||||
};
|
||||
|
||||
// initial round, subscribe once
|
||||
@ -81,7 +64,7 @@ export default function trackStream <T> (fn: TrackFn<any> | undefined, params: a
|
||||
|
||||
if (mappedParams && serialized !== tracker.current.serialized) {
|
||||
tracker.current.serialized = serialized;
|
||||
_unsubscribe();
|
||||
|
||||
_subscribe(mappedParams);
|
||||
}
|
||||
}, [params]);
|
||||
10
packages/react-hooks/src/track/types.ts
Normal file
10
packages/react-hooks/src/track/types.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2017-2019 @polkadot/react-hooks authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export type Params = [] | [any] | [any, any] | [any, any, any];
|
||||
|
||||
export interface Options <T> {
|
||||
paramMap?: (params: any) => any;
|
||||
transform?: (value: any) => T;
|
||||
}
|
||||
25
packages/react-hooks/src/track/util.ts
Normal file
25
packages/react-hooks/src/track/util.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2017-2019 @polkadot/react-hooks authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Params } from './types';
|
||||
|
||||
import { isNull, isUndefined } from '@polkadot/util';
|
||||
|
||||
export const dummyPromise = Promise.resolve((): void => {
|
||||
// we do nothing, this is a noop
|
||||
});
|
||||
|
||||
export function transformIdentity (value: any): any {
|
||||
return value;
|
||||
}
|
||||
|
||||
// extract the serialized and mapped params, all ready for use in our call
|
||||
export function extractParams (params: any[], paramMap: (params: any[]) => any): [string, Params | null] {
|
||||
return [
|
||||
JSON.stringify({ a: params }),
|
||||
params.length === 0 || !params.some((param): boolean => isNull(param) || isUndefined(null))
|
||||
? paramMap(params)
|
||||
: null
|
||||
];
|
||||
}
|
||||
30
packages/react-hooks/src/useAccounts.tsx
Normal file
30
packages/react-hooks/src/useAccounts.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2017-2019 @polkadot/react-hooks authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
|
||||
interface UseAccounts {
|
||||
allAccounts: string[];
|
||||
hasAccounts: boolean;
|
||||
}
|
||||
|
||||
export default function useAccounts (): UseAccounts {
|
||||
const [state, setState] = useState<UseAccounts>({ allAccounts: [], hasAccounts: false });
|
||||
|
||||
useEffect((): () => void => {
|
||||
const subscription = accountObservable.subject.subscribe((accounts): void => {
|
||||
const allAccounts = accounts ? Object.keys(accounts) : [];
|
||||
const hasAccounts = allAccounts.length !== 0;
|
||||
|
||||
setState({ allAccounts, hasAccounts });
|
||||
});
|
||||
|
||||
return (): void => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return state;
|
||||
}
|
||||
30
packages/react-hooks/src/useAddresses.tsx
Normal file
30
packages/react-hooks/src/useAddresses.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2017-2019 @polkadot/react-hooks authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import addressObservable from '@polkadot/ui-keyring/observable/addresses';
|
||||
|
||||
interface UseAccounts {
|
||||
allAddresses: string[];
|
||||
hasAddresses: boolean;
|
||||
}
|
||||
|
||||
export default function useAccounts (): UseAccounts {
|
||||
const [state, setState] = useState<UseAccounts>({ allAddresses: [], hasAddresses: false });
|
||||
|
||||
useEffect((): () => void => {
|
||||
const subscription = addressObservable.subject.subscribe((addresses): void => {
|
||||
const allAddresses = addresses ? Object.keys(addresses) : [];
|
||||
const hasAddresses = allAddresses.length !== 0;
|
||||
|
||||
setState({ allAddresses, hasAddresses });
|
||||
});
|
||||
|
||||
return (): void => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return state;
|
||||
}
|
||||
@ -113,47 +113,44 @@ async function loadSome (api: ApiPromise, fromHash: Hash, toHash: Hash): Promise
|
||||
export default function useSessionRewards (maxSessions: number): SessionRewards[] {
|
||||
const { api } = useApiContext();
|
||||
const [getCache, setCache] = useCacheKey<Serialized[]>('hooks:sessionSlashes');
|
||||
const [results, setResults] = useState<SessionRewards[]>(fromJSON(getCache() || []));
|
||||
const [filtered, setFiltered] = useState<SessionRewards[]>([]);
|
||||
|
||||
useEffect((): void => {
|
||||
let workQueue = results;
|
||||
let workQueue = fromJSON(getCache() || []);
|
||||
|
||||
api.isReady.then(async (): Promise<void> => {
|
||||
const maxSessionsStore = maxSessions + 1; // assuming first is a bust
|
||||
const sessionLength = (api.consts.babe?.epochDuration as BlockNumber || new BN(500));
|
||||
const count = Math.min(sessionLength.muln(maxSessionsStore).divn(10).toNumber(), 10000);
|
||||
const bestHeader = await api.rpc.chain.getHeader();
|
||||
let toHash = bestHeader.hash;
|
||||
let toNumber = bestHeader.number.unwrap().toBn();
|
||||
let fromHash = api.genesisHash;
|
||||
let fromNumber = bnMax(toNumber.subn(count), new BN(1));
|
||||
setImmediate((): void => {
|
||||
api.isReady.then(async (): Promise<void> => {
|
||||
const maxSessionsStore = maxSessions + 1; // assuming first is a bust
|
||||
const sessionLength = (api.consts.babe?.epochDuration as BlockNumber || new BN(500));
|
||||
const count = Math.min(sessionLength.muln(maxSessionsStore).divn(10).toNumber(), 10000);
|
||||
const bestHeader = await api.rpc.chain.getHeader();
|
||||
let toHash = bestHeader.hash;
|
||||
let toNumber = bestHeader.number.unwrap().toBn();
|
||||
let fromHash = api.genesisHash;
|
||||
let fromNumber = bnMax(toNumber.subn(count), new BN(1));
|
||||
|
||||
while (true) {
|
||||
fromHash = await api.rpc.chain.getBlockHash(fromNumber as any);
|
||||
while (true) {
|
||||
fromHash = await api.rpc.chain.getBlockHash(fromNumber as any);
|
||||
|
||||
const newQueue = await loadSome(api, fromHash, toHash);
|
||||
const newQueue = await loadSome(api, fromHash, toHash);
|
||||
|
||||
workQueue = mergeResults(workQueue, newQueue);
|
||||
toHash = fromHash;
|
||||
toNumber = fromNumber;
|
||||
fromNumber = bnMax(toNumber.subn(count), new BN(1));
|
||||
workQueue = mergeResults(workQueue, newQueue);
|
||||
toHash = fromHash;
|
||||
toNumber = fromNumber;
|
||||
fromNumber = bnMax(toNumber.subn(count), new BN(1));
|
||||
|
||||
setCache(toJSON(workQueue, maxSessionsStore));
|
||||
setResults(workQueue);
|
||||
setCache(toJSON(workQueue, maxSessionsStore));
|
||||
setFiltered(workQueue.slice(-maxSessions));
|
||||
|
||||
const lastNumber = workQueue[workQueue.length - 1]?.blockNumber;
|
||||
const lastNumber = workQueue[workQueue.length - 1]?.blockNumber;
|
||||
|
||||
if (!lastNumber || fromNumber.eqn(1) || ((workQueue.length >= maxSessionsStore) && fromNumber.lt(lastNumber))) {
|
||||
break;
|
||||
if (!lastNumber || fromNumber.eqn(1) || ((workQueue.length >= maxSessionsStore) && fromNumber.lt(lastNumber))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect((): void => {
|
||||
setFiltered(results.slice(-maxSessions));
|
||||
}, [results]);
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user