diff --git a/packages/apps-electron/src/index.tsx b/packages/apps-electron/src/index.tsx index dd6f7375e5..cdb879a3c6 100644 --- a/packages/apps-electron/src/index.tsx +++ b/packages/apps-electron/src/index.tsx @@ -7,6 +7,8 @@ import '@polkadot/apps/initSettings'; import 'semantic-ui-css/semantic.min.css'; import '@polkadot/react-components/i18n'; +import electron from 'electron'; +import path from 'path'; import React, { Suspense } from 'react'; import ReactDOM from 'react-dom'; import { HashRouter } from 'react-router-dom'; @@ -18,11 +20,15 @@ import { BlockAuthors, Events } from '@polkadot/react-query'; import AccountSidebar from '@polkadot/app-accounts/Sidebar'; import { Api } from '@polkadot/react-api'; import Apps from '@polkadot/apps/Apps'; +import { FileStore } from '@polkadot/ui-keyring/stores'; const rootId = 'root'; const rootElement = document.getElementById(rootId); const theme = { theme: settings.uiTheme }; +const defaultStorePath = path.join((electron.app || electron.remote.app).getPath('userData'), 'polkadot'); +const store = new FileStore(defaultStorePath); + if (!rootElement) { throw new Error(`Unable to find element with id '${rootId}'`); } @@ -33,7 +39,10 @@ ReactDOM.render( - + diff --git a/packages/page-accounts/src/Accounts/BannerExtension.tsx b/packages/page-accounts/src/Accounts/BannerExtension.tsx index a3e62a9893..6bfba2f7ff 100644 --- a/packages/page-accounts/src/Accounts/BannerExtension.tsx +++ b/packages/page-accounts/src/Accounts/BannerExtension.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { availableExtensions } from '@polkadot/apps-config/extensions'; import { isWeb3Injected } from '@polkadot/extension-dapp'; import { stringUpperFirst } from '@polkadot/util'; +import { onlyOnWeb } from '@polkadot/react-api/hoc'; import { useTranslation } from '../translate'; import Banner from './Banner'; @@ -53,4 +54,4 @@ function BannerExtension (): React.ReactElement | null { ); } -export default React.memo(BannerExtension); +export default onlyOnWeb(React.memo(BannerExtension)); diff --git a/packages/page-accounts/src/Accounts/modals/Create.tsx b/packages/page-accounts/src/Accounts/modals/Create.tsx index 9bbcf7a816..a105463584 100644 --- a/packages/page-accounts/src/Accounts/modals/Create.tsx +++ b/packages/page-accounts/src/Accounts/modals/Create.tsx @@ -17,6 +17,7 @@ import keyring from '@polkadot/ui-keyring'; import uiSettings from '@polkadot/ui-settings'; import { isHex, u8aToHex } from '@polkadot/util'; import { keyExtractSuri, mnemonicGenerate, mnemonicValidate, randomAsU8a } from '@polkadot/util-crypto'; +import { getEnvironment } from '@polkadot/react-api/util'; import { useTranslation } from '../../translate'; import CreateConfirmation from './CreateConfirmation'; @@ -132,7 +133,6 @@ export function downloadAccount ({ json, pair }: CreateResult): void { const blob = new Blob([JSON.stringify(json)], { type: 'application/json; charset=utf-8' }); FileSaver.saveAs(blob, `${pair.address}.json`); - InputAddress.setLastValue('account', pair.address); } function createAccount (suri: string, pairType: KeypairType, { genesisHash, name, tags = [] }: CreateOptions, password: string, success: string): ActionStatus { @@ -147,7 +147,11 @@ function createAccount (suri: string, pairType: KeypairType, { genesisHash, name status.status = 'success'; status.message = success; - downloadAccount(result); + InputAddress.setLastValue('account', address); + + if (getEnvironment() === 'web') { + downloadAccount(result); + } } catch (error) { status.status = 'error'; status.message = (error as Error).message; diff --git a/packages/page-accounts/src/Accounts/modals/Derive.tsx b/packages/page-accounts/src/Accounts/modals/Derive.tsx index 5c5b6b6eed..09be2c0ff8 100644 --- a/packages/page-accounts/src/Accounts/modals/Derive.tsx +++ b/packages/page-accounts/src/Accounts/modals/Derive.tsx @@ -64,6 +64,7 @@ function createAccount (source: KeyringPair, suri: string, name: string, passwor status.message = success; downloadAccount(result); + InputAddress.setLastValue('account', address); } catch (error) { status.status = 'error'; status.message = (error as Error).message; diff --git a/packages/react-api/src/Api.tsx b/packages/react-api/src/Api.tsx index f1cc2713e0..cbce6a83dd 100644 --- a/packages/react-api/src/Api.tsx +++ b/packages/react-api/src/Api.tsx @@ -15,6 +15,8 @@ import { WsProvider } from '@polkadot/rpc-provider'; import { StatusContext } from '@polkadot/react-components/Status'; import { TokenUnit } from '@polkadot/react-components/InputNumber'; import keyring from '@polkadot/ui-keyring'; +import { KeyringStore } from '@polkadot/ui-keyring/types'; + import uiSettings from '@polkadot/ui-settings'; import ApiSigner from '@polkadot/react-signer/ApiSigner'; import { formatBalance, isTestChain } from '@polkadot/util'; @@ -27,6 +29,7 @@ import registry from './typeRegistry'; interface Props { children: React.ReactNode; url?: string; + store?: KeyringStore; } interface InjectedAccountExt { @@ -94,7 +97,7 @@ async function retrieve (api: ApiPromise): Promise { }; } -async function loadOnReady (api: ApiPromise): Promise { +async function loadOnReady (api: ApiPromise, store?: KeyringStore): Promise { const { injectedAccounts, properties, systemChain, systemChainType, systemName, systemVersion } = await retrieve(api); const ss58Format = uiSettings.prefix === -1 ? properties.ss58Format.unwrapOr(DEFAULT_SS58).toNumber() @@ -123,6 +126,7 @@ async function loadOnReady (api: ApiPromise): Promise { genesisHash: api.genesisHash, isDevelopment, ss58Format, + store, type: 'ed25519' }, injectedAccounts); @@ -146,7 +150,7 @@ async function loadOnReady (api: ApiPromise): Promise { }; } -function Api ({ children, url }: Props): React.ReactElement | null { +function Api ({ children, store, url }: Props): React.ReactElement | null { const { queuePayload, queueSetTxStatus } = useContext(StatusContext); const [state, setState] = useState({ isApiReady: false } as unknown as ApiState); const [isApiConnected, setIsApiConnected] = useState(false); @@ -168,7 +172,7 @@ function Api ({ children, url }: Props): React.ReactElement | null { api.on('disconnected', () => setIsApiConnected(false)); api.on('ready', async (): Promise => { try { - setState(await loadOnReady(api)); + setState(await loadOnReady(api, store)); } catch (error) { console.error('Unable to load chain', error); } diff --git a/packages/react-api/src/hoc/index.ts b/packages/react-api/src/hoc/index.ts index 2c7c7bf828..41ac35f765 100644 --- a/packages/react-api/src/hoc/index.ts +++ b/packages/react-api/src/hoc/index.ts @@ -8,3 +8,4 @@ export { default as withCalls } from './calls'; export { default as withCallDiv } from './callDiv'; export { default as withMulti } from './multi'; export { default as withObservable } from './observable'; +export * from './onlyOn'; diff --git a/packages/react-api/src/hoc/onlyOn.tsx b/packages/react-api/src/hoc/onlyOn.tsx new file mode 100644 index 0000000000..4b1e2cfc35 --- /dev/null +++ b/packages/react-api/src/hoc/onlyOn.tsx @@ -0,0 +1,18 @@ +// Copyright 2017-2020 @polkadot/app-accounts 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 { ComponentType } from 'react'; +import { Environment } from '../types'; +import { getEnvironment } from '../util'; + +const onlyOn = (environment: Environment) => >(component: T): T | (() => null) => { + if (getEnvironment() === environment) { + return component; + } + + return () => null; +}; + +export const onlyOnWeb = onlyOn('web'); +export const onlyOnApp = onlyOn('app'); diff --git a/packages/react-api/src/types.ts b/packages/react-api/src/types.ts index c7a7b8ef82..48f540ddff 100644 --- a/packages/react-api/src/types.ts +++ b/packages/react-api/src/types.ts @@ -60,3 +60,5 @@ export type BaseProps = BareProps & CallProps & ChangeProps & { }; export type Formatter = (value?: any) => string; + +export type Environment = 'web' | 'app'; diff --git a/packages/react-api/src/util/getEnvironment.ts b/packages/react-api/src/util/getEnvironment.ts new file mode 100644 index 0000000000..e07d8bc8ff --- /dev/null +++ b/packages/react-api/src/util/getEnvironment.ts @@ -0,0 +1,26 @@ +// Copyright 2017-2020 @polkadot/app-accounts 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 { Environment } from '../types'; + +// https://github.com/electron/electron/issues/2288 +function isElectron () { + if (process?.versions?.electron) { + return true; + } + + if (window?.process?.type === 'renderer') { + return true; + } + + return navigator?.userAgent?.indexOf('Electron') >= 0; +} + +export default function getEnvironment (): Environment { + if (isElectron()) { + return 'app'; + } + + return 'web'; +} diff --git a/packages/react-api/src/util/index.ts b/packages/react-api/src/util/index.ts index 0d6fbbdde5..0f42075d1b 100644 --- a/packages/react-api/src/util/index.ts +++ b/packages/react-api/src/util/index.ts @@ -2,6 +2,7 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import getEnvironment from './getEnvironment'; import getHistoric from './historic'; import intervalObservable from './intervalObservable'; import isEqual from './isEqual'; @@ -11,5 +12,6 @@ export { getHistoric, intervalObservable, isEqual, - triggerChange + triggerChange, + getEnvironment };