Save target/overview toggles (#4249)

This commit is contained in:
Jaco Greeff 2020-12-20 12:55:10 +01:00 committed by GitHub
parent 78dd9d0fe1
commit 593b42c275
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 92 additions and 40 deletions

View File

@ -9,7 +9,7 @@ import type { SortedTargets, ValidatorInfo } from '../types';
import React, { useCallback, useContext, useMemo, useRef, useState } from 'react';
import { Table } from '@polkadot/react-components';
import { useApi, useCall, useLoadingDelay } from '@polkadot/react-hooks';
import { useApi, useCall, useLoadingDelay, useSavedFlags } from '@polkadot/react-hooks';
import { BlockAuthorsContext } from '@polkadot/react-query';
import Filtering from '../Filtering';
@ -78,7 +78,7 @@ function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, ta
const recentlyOnline = useCall<DeriveHeartbeats>(!isIntentions && api.derive.imOnline?.receivedHeartbeats);
const nominatedBy = useNominations(isIntentions);
const [nameFilter, setNameFilter] = useState<string>('');
const [withIdentity, setWithIdentity] = useState(false);
const [toggles, setToggle] = useSavedFlags('staking:overview', { withIdentity: false });
// we have a very large list, so we use a loading delay
const isLoading = useLoadingDelay();
@ -134,10 +134,10 @@ function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, ta
points={eraPoints[address]}
toggleFavorite={toggleFavorite}
validatorInfo={infoMap?.[address]}
withIdentity={withIdentity}
withIdentity={toggles.withIdentity}
/>
)),
[byAuthor, eraPoints, hasQueries, infoMap, nameFilter, nominatedBy, recentlyOnline, toggleFavorite, withIdentity]
[byAuthor, eraPoints, hasQueries, infoMap, nameFilter, nominatedBy, recentlyOnline, toggleFavorite, toggles]
);
return isIntentions
@ -155,8 +155,8 @@ function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, ta
<Filtering
nameFilter={nameFilter}
setNameFilter={setNameFilter}
setWithIdentity={setWithIdentity}
withIdentity={withIdentity}
setWithIdentity={setToggle.withIdentity}
withIdentity={toggles.withIdentity}
/>
}
header={headerWaitingRef.current}
@ -179,8 +179,8 @@ function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, ta
<Filtering
nameFilter={nameFilter}
setNameFilter={setNameFilter}
setWithIdentity={setWithIdentity}
withIdentity={withIdentity}
setWithIdentity={setToggle.withIdentity}
withIdentity={toggles.withIdentity}
/>
}
header={headerActiveRef.current}

View File

@ -10,7 +10,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components';
import { Button, Icon, Table, Toggle } from '@polkadot/react-components';
import { useApi, useAvailableSlashes, useBlocksPerDays } from '@polkadot/react-hooks';
import { useApi, useAvailableSlashes, useBlocksPerDays, useSavedFlags } from '@polkadot/react-hooks';
import { MAX_NOMINATIONS } from '../constants';
import ElectionBanner from '../ElectionBanner';
@ -33,10 +33,7 @@ interface Props {
toggleFavorite: (address: string) => void;
}
interface Flags {
daysPayout: BN;
isBabe: boolean;
maxPaid: BN | undefined;
interface SavedFlags {
withElected: boolean;
withGroup: boolean;
withIdentity: boolean;
@ -45,6 +42,12 @@ interface Flags {
withoutOver: boolean;
}
interface Flags extends SavedFlags {
daysPayout: BN;
isBabe: boolean;
maxPaid: BN | undefined;
}
interface SortState {
sortBy: TargetSortBy;
sortFromMax: boolean;
@ -180,12 +183,14 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
const allIdentity = useIdentities(validatorIds);
const [selected, setSelected] = useState<string[]>([]);
const [{ isQueryFiltered, nameFilter }, setNameFilter] = useState({ isQueryFiltered: false, nameFilter: '' });
const [withElected, setWithElected] = useState(false);
const [withGroup, setWithGroup] = useState(true);
const [withIdentity, setWithIdentity] = useState(false);
const [withPayout, setWithPayout] = useState(false);
const [withoutComm, setWithoutComm] = useState(true);
const [withoutOver, setWithoutOver] = useState(true);
const [toggles, setToggle] = useSavedFlags('staking:targets', {
withElected: false,
withGroup: true,
withIdentity: false,
withPayout: false,
withoutComm: true,
withoutOver: true
});
const [{ sortBy, sortFromMax }, setSortBy] = useState<SortState>({ sortBy: 'rankOverall', sortFromMax: true });
const [sorted, setSorted] = useState<ValidatorInfo[] | undefined>();
@ -198,18 +203,13 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
const flags = useMemo(
() => ({
...toggles,
daysPayout,
isBabe: !!api.consts.babe,
isQueryFiltered,
maxPaid: api.consts.staking?.maxNominatorRewardedPerValidator,
withElected,
withGroup,
withIdentity,
withPayout,
withoutComm,
withoutOver
maxPaid: api.consts.staking?.maxNominatorRewardedPerValidator
}),
[api, daysPayout, isQueryFiltered, withElected, withGroup, withIdentity, withPayout, withoutComm, withoutOver]
[api, daysPayout, isQueryFiltered, toggles]
);
const filtered = useMemo(
@ -282,14 +282,14 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
<Filtering
nameFilter={nameFilter}
setNameFilter={_setNameFilter}
setWithIdentity={setWithIdentity}
withIdentity={withIdentity}
setWithIdentity={setToggle.withIdentity}
withIdentity={toggles.withIdentity}
>
<Toggle
className='staking--buttonToggle'
label={t<string>('single from operator')}
onChange={setWithGroup}
value={withGroup}
onChange={setToggle.withGroup}
value={toggles.withGroup}
/>
<Toggle
className='staking--buttonToggle'
@ -298,8 +298,8 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
? t<string>('no {{maxComm}}%+ comm', { replace: { maxComm: MAX_COMM_PERCENT } })
: t<string>('no median+ comm')
}
onChange={setWithoutComm}
value={withoutComm}
onChange={setToggle.withoutComm}
value={toggles.withoutComm}
/>
<Toggle
className='staking--buttonToggle'
@ -308,27 +308,27 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
? t<string>('no {{maxCap}}%+ capacity', { replace: { maxCap: MAX_CAP_PERCENT } })
: t<string>('no at capacity')
}
onChange={setWithoutOver}
value={withoutOver}
onChange={setToggle.withoutOver}
value={toggles.withoutOver}
/>
{api.consts.babe && (
// FIXME have some sane era defaults for Aura
<Toggle
className='staking--buttonToggle'
label={t<string>('recent payouts')}
onChange={setWithPayout}
value={withPayout}
onChange={setToggle.withPayout}
value={toggles.withPayout}
/>
)}
<Toggle
className='staking--buttonToggle'
label={t<string>('only elected')}
onChange={setWithElected}
value={withElected}
onChange={setToggle.withElected}
value={toggles.withElected}
/>
</Filtering>
</div>
), [api, nameFilter, _setNameFilter, t, withElected, withGroup, withIdentity, withPayout, withoutComm, withoutOver]);
), [api, nameFilter, _setNameFilter, setToggle, t, toggles]);
const displayList = isQueryFiltered
? validators

View File

@ -29,6 +29,7 @@ export { useOwnStashes, useOwnStashIds } from './useOwnStashes';
export { useOwnStashInfos } from './useOwnStashInfos';
export { usePassword } from './usePassword';
export { useRegistrars } from './useRegistrars';
export { useSavedFlags } from './useSavedFlags';
export { useSudo } from './useSudo';
export { useToggle } from './useToggle';
export { useVotingStatus } from './useVotingStatus';

View File

@ -0,0 +1,51 @@
// Copyright 2017-2020 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { useEffect, useState } from 'react';
import store from 'store';
import { isBoolean } from '@polkadot/util';
type Flags = Record<string, boolean>;
type Setters<T extends Flags> = Record<keyof T, (value: boolean) => void>;
type State<T extends Flags> = [T, Setters<T>];
function getInitial <T extends Flags> (storageKey: string, initial: T): T {
const saved = store.get(`flags:${storageKey}`, {}) as T;
return Object.keys(initial).reduce((result, key: keyof T): T => {
if (isBoolean(saved[key])) {
result[key] = saved[key];
}
return result;
}, { ...initial });
}
function getSetters <T extends Flags> (flags: T, setFlags: React.Dispatch<React.SetStateAction<T>>): Setters<T> {
const setFlag = (key: keyof T) =>
(value: boolean) =>
setFlags((state) => ({ ...state, [key]: value }));
return Object.keys(flags).reduce((setters, key: keyof T): Setters<T> => {
setters[key] = setFlag(key);
return setters;
}, {} as Setters<T>);
}
export function useSavedFlags <T extends Flags> (storageKey: string, initial: T): State<T> {
const [flags, setFlags] = useState(getInitial(storageKey, initial));
const [setters] = useState(getSetters(initial, setFlags));
useEffect(
(): void => {
store.set(`flags:${storageKey}`, flags);
},
[flags, storageKey]
);
return [flags, setters];
}