From 2b9274c40f2de39e274ee9f21e99be885d1aa0df Mon Sep 17 00:00:00 2001 From: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> Date: Mon, 25 Jan 2021 18:20:35 +0100 Subject: [PATCH] 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 :( --- .../extension-chains/src/genesisHashes.ts | 22 ---------- packages/extension-chains/src/index.ts | 1 - .../src/Popup/Accounts/Account.tsx | 5 ++- .../src/Popup/ImportSeed/ImportSeed.test.tsx | 2 +- .../src/Popup/ImportSeed/SeedAndPath.tsx | 41 ++++++++++++------- .../src/Popup/ImportSeed/index.tsx | 11 ++++- .../extension-ui/src/components/Address.tsx | 2 +- .../extension-ui/src/components/Label.tsx | 2 +- .../extension-ui/src/components/MenuItem.tsx | 2 +- .../extension-ui/src/components/themes.ts | 1 + .../src/hooks/useGenesisHashOptions.ts | 29 +++++++++++++ packages/extension-ui/src/messaging.ts | 6 +-- .../src => extension-ui/src/util}/chains.ts | 2 +- .../extension-ui/src/util/getNetworkMap.ts | 2 +- .../public/locales/en/translation.json | 1 + .../public/locales/fr/translation.json | 1 + 16 files changed, 80 insertions(+), 50 deletions(-) delete mode 100644 packages/extension-chains/src/genesisHashes.ts create mode 100644 packages/extension-ui/src/hooks/useGenesisHashOptions.ts rename packages/{extension-chains/src => extension-ui/src/util}/chains.ts (85%) diff --git a/packages/extension-chains/src/genesisHashes.ts b/packages/extension-chains/src/genesisHashes.ts deleted file mode 100644 index 1982c5a7..00000000 --- a/packages/extension-chains/src/genesisHashes.ts +++ /dev/null @@ -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; diff --git a/packages/extension-chains/src/index.ts b/packages/extension-chains/src/index.ts index 85d9404d..454d6d00 100644 --- a/packages/extension-chains/src/index.ts +++ b/packages/extension-chains/src/index.ts @@ -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 ` -// import kusama from './kusama'; const definitions = new Map( // [kusama].map((def) => [def.genesisHash, def]) diff --git a/packages/extension-ui/src/Popup/Accounts/Account.tsx b/packages/extension-ui/src/Popup/Accounts/Account.tsx index 200418e4..13466726 100644 --- a/packages/extension-ui/src/Popup/Accounts/Account.tsx +++ b/packages/extension-ui/src/Popup/Accounts/Account.tsx @@ -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({ isEditing: false, toggleActions: 0 }); const [editedName, setName] = useState(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 (
diff --git a/packages/extension-ui/src/Popup/ImportSeed/ImportSeed.test.tsx b/packages/extension-ui/src/Popup/ImportSeed/ImportSeed.test.tsx index 9bad09a0..c5b8b17a 100644 --- a/packages/extension-ui/src/Popup/ImportSeed/ImportSeed.test.tsx +++ b/packages/extension-ui/src/Popup/ImportSeed/ImportSeed.test.tsx @@ -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('/'); }); }); diff --git a/packages/extension-ui/src/Popup/ImportSeed/SeedAndPath.tsx b/packages/extension-ui/src/Popup/ImportSeed/SeedAndPath.tsx index 05d8a7cc..67969cd3 100644 --- a/packages/extension-ui/src/Popup/ImportSeed/SeedAndPath.tsx +++ b/packages/extension-ui/src/Popup/ImportSeed/SeedAndPath.tsx @@ -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(null); const [path, setPath] = useState(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('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('Mnemonic needs to contain 12, 15, 18, 21, 24 words')} )} + ('Network')} + onChange={setGenesis} + options={genesisOptions} + value={genesis} + />
` +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; } diff --git a/packages/extension-ui/src/Popup/ImportSeed/index.tsx b/packages/extension-ui/src/Popup/ImportSeed/index.tsx index 0f3184a7..6408419a 100644 --- a/packages/extension-ui/src/Popup/ImportSeed/index.tsx +++ b/packages/extension-ui/src/Popup/ImportSeed/index.tsx @@ -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); + const [account, setAccount] = useState(null); const [name, setName] = useState(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 {
diff --git a/packages/extension-ui/src/components/Address.tsx b/packages/extension-ui/src/components/Address.tsx index b13e34bf..84699595 100644 --- a/packages/extension-ui/src/components/Address.tsx +++ b/packages/extension-ui/src/components/Address.tsx @@ -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; diff --git a/packages/extension-ui/src/components/Label.tsx b/packages/extension-ui/src/components/Label.tsx index 8c3d702f..769a68b5 100644 --- a/packages/extension-ui/src/components/Label.tsx +++ b/packages/extension-ui/src/components/Label.tsx @@ -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; diff --git a/packages/extension-ui/src/components/MenuItem.tsx b/packages/extension-ui/src/components/MenuItem.tsx index 7cd5cfba..6c720077 100644 --- a/packages/extension-ui/src/components/MenuItem.tsx +++ b/packages/extension-ui/src/components/MenuItem.tsx @@ -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; diff --git a/packages/extension-ui/src/components/themes.ts b/packages/extension-ui/src/components/themes.ts index 9ed58200..f73a946e 100644 --- a/packages/extension-ui/src/components/themes.ts +++ b/packages/extension-ui/src/components/themes.ts @@ -32,6 +32,7 @@ const darkTheme = { identiconBackground: '#F4F5F8', inputBackground: '#111218', inputBorderColor: '#43444B', + inputLabelFontSize: '10px', labelColor: '#9F9E99', labelFontSize: '13px', labelLineHeight: '18px', diff --git a/packages/extension-ui/src/hooks/useGenesisHashOptions.ts b/packages/extension-ui/src/hooks/useGenesisHashOptions.ts new file mode 100644 index 00000000..9479d2fa --- /dev/null +++ b/packages/extension-ui/src/hooks/useGenesisHashOptions.ts @@ -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; +} diff --git a/packages/extension-ui/src/messaging.ts b/packages/extension-ui/src/messaging.ts index 72b729a7..c8bf90ca 100644 --- a/packages/extension-ui/src/messaging.ts +++ b/packages/extension-ui/src/messaging.ts @@ -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 { - 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 { + return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type }); } export async function createSeed (length?: SeedLengths, type?: KeypairType): Promise<{ address: string; seed: string }> { diff --git a/packages/extension-chains/src/chains.ts b/packages/extension-ui/src/util/chains.ts similarity index 85% rename from packages/extension-chains/src/chains.ts rename to packages/extension-ui/src/util/chains.ts index eb703d1d..27a7d00e 100644 --- a/packages/extension-chains/src/chains.ts +++ b/packages/extension-ui/src/util/chains.ts @@ -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'; diff --git a/packages/extension-ui/src/util/getNetworkMap.ts b/packages/extension-ui/src/util/getNetworkMap.ts index 3265d293..56e29a76 100644 --- a/packages/extension-ui/src/util/getNetworkMap.ts +++ b/packages/extension-ui/src/util/getNetworkMap.ts @@ -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 { const res = new Map(); diff --git a/packages/extension/public/locales/en/translation.json b/packages/extension/public/locales/en/translation.json index b534d8a0..23541803 100644 --- a/packages/extension/public/locales/en/translation.json +++ b/packages/extension/public/locales/en/translation.json @@ -152,5 +152,6 @@ "Refresh": "", "Import Account": "", "Sign on Ledger": "", + "Allow use on any chain": "", "Select network": "" } diff --git a/packages/extension/public/locales/fr/translation.json b/packages/extension/public/locales/fr/translation.json index 3c4f326c..2cc135f0 100644 --- a/packages/extension/public/locales/fr/translation.json +++ b/packages/extension/public/locales/fr/translation.json @@ -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" }