Electron app: save accounts to FS, do not download backup, hide warning banner (#2880)
* Electron app: save accounts to FS, do not download backup, hide warning banner * extract store
This commit is contained in:
parent
314e038b88
commit
368fefef72
@ -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(
|
||||
<Suspense fallback='...'>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Queue>
|
||||
<Api url={settings.apiUrl}>
|
||||
<Api
|
||||
store={store}
|
||||
url={settings.apiUrl}
|
||||
>
|
||||
<BlockAuthors>
|
||||
<Events>
|
||||
<AccountSidebar>
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<ChainData> {
|
||||
};
|
||||
}
|
||||
|
||||
async function loadOnReady (api: ApiPromise): Promise<ApiState> {
|
||||
async function loadOnReady (api: ApiPromise, store?: KeyringStore): Promise<ApiState> {
|
||||
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<ApiState> {
|
||||
genesisHash: api.genesisHash,
|
||||
isDevelopment,
|
||||
ss58Format,
|
||||
store,
|
||||
type: 'ed25519'
|
||||
}, injectedAccounts);
|
||||
|
||||
@ -146,7 +150,7 @@ async function loadOnReady (api: ApiPromise): Promise<ApiState> {
|
||||
};
|
||||
}
|
||||
|
||||
function Api ({ children, url }: Props): React.ReactElement<Props> | null {
|
||||
function Api ({ children, store, url }: Props): React.ReactElement<Props> | null {
|
||||
const { queuePayload, queueSetTxStatus } = useContext(StatusContext);
|
||||
const [state, setState] = useState<ApiState>({ isApiReady: false } as unknown as ApiState);
|
||||
const [isApiConnected, setIsApiConnected] = useState(false);
|
||||
@ -168,7 +172,7 @@ function Api ({ children, url }: Props): React.ReactElement<Props> | null {
|
||||
api.on('disconnected', () => setIsApiConnected(false));
|
||||
api.on('ready', async (): Promise<void> => {
|
||||
try {
|
||||
setState(await loadOnReady(api));
|
||||
setState(await loadOnReady(api, store));
|
||||
} catch (error) {
|
||||
console.error('Unable to load chain', error);
|
||||
}
|
||||
|
||||
@ -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';
|
||||
|
||||
18
packages/react-api/src/hoc/onlyOn.tsx
Normal file
18
packages/react-api/src/hoc/onlyOn.tsx
Normal file
@ -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) => <T extends ComponentType<any>>(component: T): T | (() => null) => {
|
||||
if (getEnvironment() === environment) {
|
||||
return component;
|
||||
}
|
||||
|
||||
return () => null;
|
||||
};
|
||||
|
||||
export const onlyOnWeb = onlyOn('web');
|
||||
export const onlyOnApp = onlyOn('app');
|
||||
@ -60,3 +60,5 @@ export type BaseProps<T> = BareProps & CallProps & ChangeProps & {
|
||||
};
|
||||
|
||||
export type Formatter = (value?: any) => string;
|
||||
|
||||
export type Environment = 'web' | 'app';
|
||||
|
||||
26
packages/react-api/src/util/getEnvironment.ts
Normal file
26
packages/react-api/src/util/getEnvironment.ts
Normal file
@ -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';
|
||||
}
|
||||
@ -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
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user