Add network selector when importing an account with mnemonic, and refactor (#627)

* add network selector and refactor

* fr trad that didnot apprear before

* with useRef

* font-size

* nit still failing

* and that work .. but not what I need

* giving up on the test :(
This commit is contained in:
Thibaut Sardan 2021-01-25 18:20:35 +01:00 committed by GitHub
parent 153c691057
commit 2b9274c40f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 80 additions and 50 deletions

View File

@ -1,22 +0,0 @@
// Copyright 2019-2021 @polkadot/extension-chains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import chains from './chains';
interface Option {
text: string;
value: string;
}
const hashes: Option[] = [
{
text: 'Allow use on any chain',
value: ''
},
...chains.map(({ chain, genesisHash }) => ({
text: chain,
value: genesisHash
}))
];
export default hashes;

View File

@ -10,7 +10,6 @@ import { base64Decode } from '@polkadot/util-crypto';
// imports chain details, generally metadata. For the generation of these,
// inside the api, run `yarn chain:info --ws <url>`
// import kusama from './kusama';
const definitions = new Map<string, MetadataDef>(
// [kusama].map((def) => [def.genesisHash, def])

View File

@ -7,9 +7,9 @@ import React, { useCallback, useContext, useMemo, useState } from 'react';
import styled from 'styled-components';
import { canDerive } from '@polkadot/extension-base/utils';
import genesisOptions from '@polkadot/extension-chains/genesisHashes';
import { ActionContext, Address, Dropdown, Link, MenuDivider } from '../../components';
import useGenesisHashOptions from '../../hooks/useGenesisHashOptions';
import useTranslation from '../../hooks/useTranslation';
import { editAccount, tieAccount } from '../../messaging';
import { Name } from '../../partials';
@ -29,6 +29,7 @@ function Account ({ address, className, genesisHash, isExternal, isHardware, isH
const onAction = useContext(ActionContext);
const [{ isEditing, toggleActions }, setEditing] = useState<EditState>({ isEditing: false, toggleActions: 0 });
const [editedName, setName] = useState<string | null>(null);
const genesisOptions = useGenesisHashOptions();
const _onChangeGenesis = useCallback(
(genesisHash?: string | null): void => {
@ -103,7 +104,7 @@ function Account ({ address, className, genesisHash, isExternal, isHardware, isH
</>
)}
</>
), [_onChangeGenesis, _toggleEdit, address, genesisHash, isExternal, isHardware, t, type]);
), [_onChangeGenesis, _toggleEdit, address, genesisHash, genesisOptions, isExternal, isHardware, t, type]);
return (
<div className={className}>

View File

@ -174,7 +174,7 @@ describe('ImportSeed', () => {
await act(flushAllPromises);
wrapper.update();
expect(messaging.createAccountSuri).toBeCalledWith(account.name, account.password, suri);
expect(messaging.createAccountSuri).toBeCalledWith(account.name, account.password, suri, undefined, '');
expect(onActionStub).toBeCalledWith('/');
});
});

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { ThemeProps } from '../../types';
import type { AccountInfo } from '.';
import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@ -10,27 +11,25 @@ import styled from 'styled-components';
import { validateSeed } from '@polkadot/extension-ui/messaging';
import { ButtonArea, InputWithLabel, NextStepButton, TextAreaWithLabel, VerticalSpace, Warning } from '../../components';
import { ButtonArea, Dropdown, InputWithLabel, NextStepButton, TextAreaWithLabel, VerticalSpace, Warning } from '../../components';
import useGenesisHashOptions from '../../hooks/useGenesisHashOptions';
import useTranslation from '../../hooks/useTranslation';
interface AccountInfo {
address: string;
suri: string;
}
interface Props {
className? : string;
onNextStep: () => void;
onAccountChange: (account: AccountInfo | null) => void;
}
function ImportSeed ({ className, onAccountChange, onNextStep }: Props): React.ReactElement {
function SeedAndPath ({ className, onAccountChange, onNextStep }: Props): React.ReactElement {
const { t } = useTranslation();
const genesisOptions = useGenesisHashOptions();
const [address, setAddress] = useState('');
const [seed, setSeed] = useState<string | null>(null);
const [path, setPath] = useState<string | null>(null);
const [advanced, setAdvances] = useState(false);
const [error, setError] = useState('');
const [genesis, setGenesis] = useState('');
useEffect(() => {
// No need to validate an empty seed
@ -43,9 +42,12 @@ function ImportSeed ({ className, onAccountChange, onNextStep }: Props): React.R
const suri = `${seed || ''}${path || ''}`;
validateSeed(suri).then((newAccount) => {
validateSeed(suri).then((validatedAccount) => {
setError('');
setAddress(newAccount.address);
setAddress(validatedAccount.address);
// a spread operator here breaks tests, using Object.assign as a workaround
const newAccount: AccountInfo = Object.assign(validatedAccount, { genesis });
onAccountChange(newAccount);
}).catch(() => {
setAddress('');
@ -55,7 +57,7 @@ function ImportSeed ({ className, onAccountChange, onNextStep }: Props): React.R
: t<string>('Invalid mnemonic seed')
);
});
}, [t, seed, path, onAccountChange]);
}, [t, seed, path, onAccountChange, genesis]);
const _onToggleAdvanced = useCallback(() => {
setAdvances(!advanced);
@ -82,6 +84,13 @@ function ImportSeed ({ className, onAccountChange, onNextStep }: Props): React.R
{t<string>('Mnemonic needs to contain 12, 15, 18, 21, 24 words')}
</Warning>
)}
<Dropdown
className='genesisSelection'
label={t<string>('Network')}
onChange={setGenesis}
options={genesisOptions}
value={genesis}
/>
<div
className='advancedToggle'
onClick={_onToggleAdvanced}
@ -119,24 +128,28 @@ function ImportSeed ({ className, onAccountChange, onNextStep }: Props): React.R
);
}
export default styled(ImportSeed)(({ theme }: ThemeProps) => `
export default styled(SeedAndPath)(({ theme }: ThemeProps) => `
.advancedToggle {
color: ${theme.textColor};
cursor: pointer;
line-height: 14px;
line-height: ${theme.lineHeight};
letter-spacing: 0.04em;
opacity: 0.65;
text-transform: uppercase;
> span {
font-size: 10px;
font-size: ${theme.inputLabelFontSize};
margin-left: .5rem;
vertical-align: middle;
}
}
.genesisSelection {
margin-bottom: ${theme.fontSize};
}
.seedInput {
margin-bottom: 16px;
margin-bottom: ${theme.fontSize};
textarea {
height: unset;
}

View File

@ -10,12 +10,18 @@ import { createAccountSuri } from '../../messaging';
import { HeaderWithSteps } from '../../partials';
import SeedAndPath from './SeedAndPath';
export interface AccountInfo {
address: string;
genesis?: string;
suri: string;
}
function ImportSeed (): React.ReactElement {
const { t } = useTranslation();
const { accounts } = useContext(AccountContext);
const onAction = useContext(ActionContext);
const [isBusy, setIsBusy] = useState(false);
const [account, setAccount] = useState<null | { address: string; suri: string }>(null);
const [account, setAccount] = useState<AccountInfo | null>(null);
const [name, setName] = useState<string | null>(null);
const [step1, setStep1] = useState(true);
@ -28,7 +34,7 @@ function ImportSeed (): React.ReactElement {
if (name && password && account) {
setIsBusy(true);
createAccountSuri(name, password, account.suri)
createAccountSuri(name, password, account.suri, undefined, account.genesis)
.then(() => onAction('/'))
.catch((error): void => {
setIsBusy(false);
@ -49,6 +55,7 @@ function ImportSeed (): React.ReactElement {
<div>
<Address
address={account?.address}
genesisHash={account?.genesis}
name={name}
/>
</div>

View File

@ -396,7 +396,7 @@ export default styled(Address)(({ theme }: ThemeProps) => `
.parentName {
color: ${theme.labelColor};
font-size: 10px;
font-size: ${theme.inputLabelFontSize};
line-height: 14px;
overflow: hidden;
padding: 0.25rem 0 0 0.8rem;

View File

@ -25,7 +25,7 @@ export default styled(Label)(({ theme }: ThemeProps) => `
color: ${theme.textColor};
label {
font-size: 10px;
font-size: ${theme.inputLabelFontSize};
line-height: 14px;
letter-spacing: 0.04em;
opacity: 0.65;

View File

@ -32,7 +32,7 @@ export default styled(MenuItem)(({ theme }: ThemeProps) => `
> .itemTitle {
margin: 0;
width: 100%;
font-size: 10px;
font-size: ${theme.inputLabelFontSize};
line-height: 14px;
letter-spacing: 0.04em;
text-transform: uppercase;

View File

@ -32,6 +32,7 @@ const darkTheme = {
identiconBackground: '#F4F5F8',
inputBackground: '#111218',
inputBorderColor: '#43444B',
inputLabelFontSize: '10px',
labelColor: '#9F9E99',
labelFontSize: '13px',
labelLineHeight: '18px',

View File

@ -0,0 +1,29 @@
// Copyright 2019-2021 @polkadot/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { useRef } from 'react';
import chains from '../util/chains';
import useTranslation from './useTranslation';
interface Option {
text: string;
value: string;
}
export default function (): Option[] {
const { t } = useTranslation();
const { current: hashes } = useRef([
{
text: t('Allow use on any chain'),
value: ''
},
...chains.map(({ chain, genesisHash }) => ({
text: chain,
value: genesisHash
}))
]);
return hashes;
}

View File

@ -9,9 +9,9 @@ import type { KeypairType } from '@polkadot/util-crypto/types';
import { PORT_EXTENSION } from '@polkadot/extension-base/defaults';
import { metadataExpand } from '@polkadot/extension-chains';
import allChains from '@polkadot/extension-chains/chains';
import chrome from '@polkadot/extension-inject/chrome';
import allChains from './util/chains';
import { getSavedMeta, setSavedMeta } from './MetadataCache';
interface Handler {
@ -121,8 +121,8 @@ export async function createAccountHardware (address: string, hardwareType: stri
return sendMessage('pri(accounts.create.hardware)', { accountIndex, address, addressOffset, genesisHash, hardwareType, name });
}
export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType): Promise<boolean> {
return sendMessage('pri(accounts.create.suri)', { name, password, suri, type });
export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType, genesisHash?: string): Promise<boolean> {
return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type });
}
export async function createSeed (length?: SeedLengths, type?: KeypairType): Promise<{ address: string; seed: string }> {

View File

@ -1,4 +1,4 @@
// Copyright 2019-2021 @polkadot/extension-chains authors & contributors
// Copyright 2019-2021 @polkadot/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { MetadataDefBase } from '@polkadot/extension-inject/types';

View File

@ -1,7 +1,7 @@
// Copyright 2019-2021 @polkadot/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
import chains from '@polkadot/extension-chains/chains';
import chains from './chains';
export default function getNetworkMap (): Map<string, string> {
const res = new Map<string, string>();

View File

@ -152,5 +152,6 @@
"Refresh": "",
"Import Account": "",
"Sign on Ledger": "",
"Allow use on any chain": "",
"Select network": ""
}

View File

@ -152,5 +152,6 @@
"Refresh": "Rafraichir",
"Import Account": "Importer",
"Sign on Ledger": "Signer sur Ledger",
"Allow use on any chain": "Toutes les blockchains",
"Select network": "Sélectionner un réseau"
}