Merge pull request #37 from andrerfneves/feature/settings-export
Feature/settings export
This commit is contained in:
commit
7ab19e0029
|
@ -17,7 +17,8 @@ const DefaultButton = styled.button`
|
|||
outline: none;
|
||||
min-width: 100px;
|
||||
border-radius: 100px;
|
||||
transition: background-color 0.1s ${props => props.theme.colors.transitionEase};
|
||||
transition: background-color 0.1s
|
||||
${props => props.theme.colors.transitionEase};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
|
@ -66,7 +67,7 @@ const Icon = styled.img`
|
|||
type Props = {
|
||||
label: string,
|
||||
onClick?: () => void,
|
||||
to?: string,
|
||||
to?: ?string,
|
||||
variant?: 'primary' | 'secondary',
|
||||
disabled?: boolean,
|
||||
icon?: string,
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// @flow
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { Button } from './button';
|
||||
|
||||
type Props = {
|
||||
text: string,
|
||||
className?: string,
|
||||
};
|
||||
|
||||
type State = { copied: boolean };
|
||||
|
||||
export class Clipboard extends PureComponent<Props, State> {
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
};
|
||||
|
||||
state = {
|
||||
copied: false,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
const { text } = this.props;
|
||||
|
||||
const el = document.createElement('textarea');
|
||||
el.value = text;
|
||||
|
||||
if (document.body) document.body.appendChild(el);
|
||||
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
if (document.body) document.body.removeChild(el);
|
||||
|
||||
this.setState({ copied: true });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
const { copied } = this.state;
|
||||
|
||||
return (
|
||||
<Button
|
||||
label={copied ? 'Copied!' : 'Copy!'}
|
||||
className={className}
|
||||
onClick={this.handleClick}
|
||||
disabled={copied}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// @flow
|
||||
import React, { type Element } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { TextComponent } from './text';
|
||||
import { Button } from './button';
|
||||
import { Divider } from './divider';
|
||||
import { ModalComponent } from './modal';
|
||||
|
||||
import CloseIcon from '../assets/images/close_icon.svg';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
width: ${props => `${props.width}px`};
|
||||
background-color: ${props => props.theme.colors.background};
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 0px 30px 0px black;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const CloseIconWrapper = styled.div`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
position: absolute;
|
||||
`;
|
||||
|
||||
const TitleWrapper = styled.div`
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
`;
|
||||
|
||||
const CloseIconImg = styled.img`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 12px;
|
||||
margin-right: 12px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const Btn = styled(Button)`
|
||||
width: 95%;
|
||||
margin-bottom: 10px;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
renderTrigger: (() => void) => Element<*>,
|
||||
title: string,
|
||||
onConfirm: () => void,
|
||||
showButtons?: boolean,
|
||||
width?: number,
|
||||
isLoading?: boolean,
|
||||
children: Element<*>,
|
||||
};
|
||||
|
||||
export const ConfirmDialogComponent = ({
|
||||
children,
|
||||
title,
|
||||
onConfirm,
|
||||
renderTrigger,
|
||||
showButtons,
|
||||
isLoading,
|
||||
width,
|
||||
}: Props) => (
|
||||
<ModalComponent
|
||||
renderTrigger={renderTrigger}
|
||||
closeOnBackdropClick={false}
|
||||
closeOnEsc={false}
|
||||
>
|
||||
{toggle => (
|
||||
<Wrapper width={width}>
|
||||
<CloseIconWrapper>
|
||||
<CloseIconImg src={CloseIcon} onClick={toggle} />
|
||||
</CloseIconWrapper>
|
||||
<TitleWrapper>
|
||||
<TextComponent value={title} align='center' />
|
||||
</TitleWrapper>
|
||||
<Divider />
|
||||
{React.Children.map(children, _ => _)}
|
||||
{showButtons && (
|
||||
<>
|
||||
<Btn label='Confirm' onClick={onConfirm} isLoading={isLoading} />
|
||||
<Btn
|
||||
label='Cancel'
|
||||
onClick={toggle}
|
||||
variant='secondary'
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Wrapper>
|
||||
)}
|
||||
</ModalComponent>
|
||||
);
|
||||
|
||||
ConfirmDialogComponent.defaultProps = {
|
||||
showButtons: true,
|
||||
width: 460,
|
||||
isLoading: false,
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
name: Confirm Dialog
|
||||
---
|
||||
|
||||
import { Playground, PropsTable } from 'docz'
|
||||
|
||||
import { Button } from './button.js'
|
||||
import { ConfirmDialogComponent } from './confirm-dialog.js'
|
||||
import { DoczWrapper } from '../theme.js'
|
||||
|
||||
# Confirm Dialog
|
||||
|
||||
## Properties
|
||||
|
||||
<PropsTable of={ConfirmDialogComponent} />
|
||||
|
||||
## Basic Usage
|
||||
|
||||
<Playground>
|
||||
<DoczWrapper>
|
||||
{() => (
|
||||
<ConfirmDialogComponent
|
||||
title="Confirm example"
|
||||
onConfirm={() => alert('Confirm')}
|
||||
renderTrigger={toggle => <button onClick={toggle}> Open! </button>}
|
||||
>
|
||||
<div>Confirm content</div>
|
||||
</ConfirmDialogComponent>
|
||||
)}
|
||||
</DoczWrapper>
|
||||
</Playground>
|
|
@ -4,18 +4,14 @@ import React from 'react';
|
|||
import styled from 'styled-components';
|
||||
|
||||
const getDefaultStyles = t => styled[t]`
|
||||
border-radius: ${// $FlowFixMe
|
||||
props => props.theme.boxBorderRadius};
|
||||
border-radius: ${props => props.theme.boxBorderRadius};
|
||||
border: none;
|
||||
background-color: ${// $FlowFixMe
|
||||
props => props.theme.colors.inputBackground};
|
||||
color: ${// $FlowFixMe
|
||||
props => props.theme.colors.text};
|
||||
background-color: ${props => props.theme.colors.inputBackground};
|
||||
color: ${props => props.theme.colors.text};
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
font-family: ${// $FlowFixMe
|
||||
props => props.theme.fontFamily};
|
||||
font-family: ${props => props.theme.fontFamily};
|
||||
|
||||
::placeholder {
|
||||
opacity: 0.5;
|
||||
|
@ -28,7 +24,7 @@ const Textarea = getDefaultStyles('textarea');
|
|||
type Props = {
|
||||
inputType?: 'input' | 'textarea',
|
||||
value: string,
|
||||
onChange: string => void,
|
||||
onChange?: string => void,
|
||||
onFocus?: (SyntheticFocusEvent<HTMLInputElement>) => void,
|
||||
rows?: number,
|
||||
disabled?: boolean,
|
||||
|
@ -36,7 +32,11 @@ type Props = {
|
|||
step?: number,
|
||||
};
|
||||
|
||||
export const InputComponent = ({ inputType, onChange, ...props }: Props) => {
|
||||
export const InputComponent = ({
|
||||
inputType,
|
||||
onChange = () => {},
|
||||
...props
|
||||
}: Props) => {
|
||||
const inputTypes = {
|
||||
input: () => (
|
||||
<Input onChange={evt => onChange(evt.target.value)} {...props} />
|
||||
|
|
|
@ -43,7 +43,7 @@ const StyledLink = styled(Link)`
|
|||
color: ${/* eslint-disable-next-line max-len */
|
||||
props => (props.isActive
|
||||
? props.theme.colors.sidebarItemActive
|
||||
: props.theme.colors.sidebarHoveredItemLabel)};
|
||||
: '#ddd')}
|
||||
background-color: ${props => props.theme.colors.sidebarHoveredItem};
|
||||
}
|
||||
`;
|
||||
|
@ -54,7 +54,7 @@ const Icon = styled.img`
|
|||
margin-right: 13px;
|
||||
|
||||
${StyledLink}:hover & {
|
||||
filter: ${props => (props.isActive ? 'none' : 'brightness(200%)')};
|
||||
filter: ${props => (props.isActive ? 'none' : 'brightness(300%)')};
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -83,7 +83,7 @@ export const SidebarComponent = ({ options, location }: Props) => (
|
|||
<Icon
|
||||
isActive={isActive}
|
||||
src={item.icon(isActive)}
|
||||
alt={`Sidebar Icon ${item.route}`}
|
||||
alt={`${item.route}`}
|
||||
/>
|
||||
{item.label}
|
||||
</StyledLink>
|
||||
|
|
|
@ -26,7 +26,7 @@ const Wrapper = styled.div`
|
|||
display: flex;
|
||||
background-color: #000;
|
||||
border-radius: 27px;
|
||||
padding: 7px 13px;
|
||||
padding: 8px 16px;
|
||||
`;
|
||||
|
||||
const Icon = styled.img`
|
||||
|
@ -41,6 +41,8 @@ const StatusPillLabel = styled(TextComponent)`
|
|||
color: ${props => props.theme.colors.statusPillLabel};
|
||||
font-weight: ${props => props.theme.fontWeight.bold};
|
||||
text-transform: uppercase;
|
||||
font-size: 10px;
|
||||
padding-top: 1px;
|
||||
`;
|
||||
|
||||
type Props = {};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// @flow
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { SettingsView } from '../views/settings';
|
||||
|
||||
import type { AppState } from '../types/app-state';
|
||||
|
||||
const mapStateToProps = ({ walletSummary }: AppState) => ({
|
||||
addresses: walletSummary.addresses,
|
||||
});
|
||||
|
||||
export const SettingsContainer = connect(mapStateToProps)(SettingsView);
|
|
@ -10,7 +10,7 @@ import { DashboardContainer } from '../containers/dashboard';
|
|||
import { TransactionsContainer } from '../containers/transactions';
|
||||
import { SendContainer } from '../containers/send';
|
||||
import { ReceiveContainer } from '../containers/receive';
|
||||
import { SettingsView } from '../views/settings';
|
||||
import { SettingsContainer } from '../containers/settings';
|
||||
import { NotFoundView } from '../views/not-found';
|
||||
import { ConsoleView } from '../views/console';
|
||||
import { LayoutComponent } from '../components/layout';
|
||||
|
@ -59,7 +59,7 @@ export const RouterComponent = ({ location }: { location: Location }) => (
|
|||
/>
|
||||
<Route path={SEND_ROUTE} component={SendContainer} />
|
||||
<Route path={RECEIVE_ROUTE} component={ReceiveContainer} />
|
||||
<Route path={SETTINGS_ROUTE} component={SettingsView} />
|
||||
<Route path={SETTINGS_ROUTE} component={SettingsContainer} />
|
||||
<Route path={CONSOLE_ROUTE} component={ConsoleView} />
|
||||
<Route
|
||||
path={TRANSACTIONS_ROUTE}
|
||||
|
|
|
@ -10,14 +10,15 @@ import { DARK } from './constants/themes';
|
|||
const darkOne = '#F4B728';
|
||||
const lightOne = '#ffffff';
|
||||
const brandOne = '#000';
|
||||
const brandTwo = '#3B3B3F';
|
||||
// const brandTwo = '#3B3B3F';
|
||||
const brandThree = '#5d5d65';
|
||||
const activeItem = '#F4B728';
|
||||
const text = '#FFF';
|
||||
const cardBackgroundColor = '#000';
|
||||
const sidebarLogoGradientBegin = '#F4B728';
|
||||
const sidebarLogoGradientEnd = '#FFE240';
|
||||
const sidebarHoveredItem = '#1C1C1C';
|
||||
const sidebarHoveredItemLabel = '#76767e';
|
||||
const sidebarHoveredItemLabel = '#8e8e96';
|
||||
const background = '#212124';
|
||||
const transactionSent = '#FF6C6C';
|
||||
const transactionReceived = '#6AEAC0';
|
||||
|
@ -51,14 +52,14 @@ const appTheme = {
|
|||
dark: lightOne,
|
||||
}),
|
||||
sidebarBg: brandOne,
|
||||
sidebarItem: brandTwo,
|
||||
sidebarItem: brandThree,
|
||||
sidebarItemActive: activeItem,
|
||||
sidebarHoveredItem,
|
||||
sidebarHoveredItemLabel,
|
||||
cardBackgroundColor,
|
||||
text,
|
||||
activeItem,
|
||||
inactiveItem: brandTwo,
|
||||
inactiveItem: brandThree,
|
||||
sidebarLogoGradientBegin,
|
||||
sidebarLogoGradientEnd,
|
||||
background,
|
||||
|
|
|
@ -1,5 +1,292 @@
|
|||
// @flow
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import fs from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import React, { PureComponent } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import electron from 'electron';
|
||||
import isDev from 'electron-is-dev';
|
||||
import dateFns from 'date-fns';
|
||||
import eres from 'eres';
|
||||
|
||||
import React from 'react';
|
||||
import { Button } from '../components/button';
|
||||
import { ConfirmDialogComponent } from '../components/confirm-dialog';
|
||||
import { TextComponent } from '../components/text';
|
||||
import { InputComponent } from '../components/input';
|
||||
import { InputLabelComponent } from '../components/input-label';
|
||||
import { RowComponent } from '../components/row';
|
||||
import { Clipboard } from '../components/clipboard';
|
||||
|
||||
export const SettingsView = () => <div className='settings'>settings</div>;
|
||||
import rpc from '../../services/api';
|
||||
|
||||
const HOME_DIR = electron.remote.app.getPath('home');
|
||||
|
||||
const Wrapper = styled.div`
|
||||
margin-top: ${props => props.theme.layoutContentPaddingTop};
|
||||
`;
|
||||
|
||||
const ModalContent = styled.div`
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
|
||||
p {
|
||||
word-break: break-all;
|
||||
}
|
||||
`;
|
||||
|
||||
const Btn = styled(Button)`
|
||||
margin-bottom: 10px;
|
||||
`;
|
||||
|
||||
const ClipboardButton = styled(Clipboard)`
|
||||
width: 50px;
|
||||
border-radius: ${props => props.theme.boxBorderRadius};
|
||||
height: 45px;
|
||||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
type Key = {
|
||||
zAddress: string,
|
||||
key: string,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
addresses: string[],
|
||||
};
|
||||
type State = {
|
||||
viewKeys: Key[],
|
||||
privateKeys: Key[],
|
||||
importedPrivateKeys: string,
|
||||
successExportViewKeys: boolean,
|
||||
successExportPrivateKeys: boolean,
|
||||
successImportPrivateKeys: boolean,
|
||||
isLoading: boolean,
|
||||
error: string | null,
|
||||
};
|
||||
|
||||
export class SettingsView extends PureComponent<Props, State> {
|
||||
state = {
|
||||
viewKeys: [],
|
||||
privateKeys: [],
|
||||
importedPrivateKeys: '',
|
||||
isLoading: false,
|
||||
successExportViewKeys: false,
|
||||
successExportPrivateKeys: false,
|
||||
successImportPrivateKeys: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
exportViewKeys = () => {
|
||||
const { addresses } = this.props;
|
||||
|
||||
const zAddresses = addresses.filter(addr => addr.startsWith('z'));
|
||||
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
Promise.all(
|
||||
zAddresses.map(async (zAddr) => {
|
||||
const viewKey = await rpc.z_exportviewingkey(zAddr);
|
||||
return { zAddress: zAddr, key: viewKey };
|
||||
}),
|
||||
).then((viewKeys) => {
|
||||
this.setState({
|
||||
viewKeys,
|
||||
successExportViewKeys: true,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exportPrivateKeys = () => {
|
||||
const { addresses } = this.props;
|
||||
|
||||
const zAddresses = addresses.filter(addr => addr.startsWith('z'));
|
||||
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
Promise.all(
|
||||
zAddresses.map(async (zAddr) => {
|
||||
const privateKey = await rpc.z_exportkey(zAddr);
|
||||
return { zAddress: zAddr, key: privateKey };
|
||||
}),
|
||||
).then((privateKeys) => {
|
||||
this.setState({
|
||||
privateKeys,
|
||||
successExportPrivateKeys: true,
|
||||
isLoading: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
importPrivateKeys = () => {
|
||||
const { importedPrivateKeys } = this.state;
|
||||
|
||||
if (!importedPrivateKeys) return;
|
||||
|
||||
const keys = importedPrivateKeys
|
||||
.split('\n')
|
||||
.map(key => key.trim())
|
||||
.filter(key => !!key);
|
||||
|
||||
this.setState({ isLoading: true, error: null });
|
||||
|
||||
Promise.all(keys.map(key => rpc.z_importkey(key)))
|
||||
.then(() => {
|
||||
this.setState({
|
||||
successImportPrivateKeys: true,
|
||||
isLoading: false,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ isLoading: false, error: error.message });
|
||||
});
|
||||
};
|
||||
|
||||
backupWalletDat = async () => {
|
||||
const backupFileName = `zcash-wallet-backup-${dateFns.format(
|
||||
new Date(),
|
||||
'YYYY-MM-DD-mm-ss',
|
||||
)}.dat`;
|
||||
|
||||
electron.remote.dialog.showSaveDialog(
|
||||
{ defaultPath: backupFileName },
|
||||
async (pathToSave) => {
|
||||
if (!pathToSave) return;
|
||||
|
||||
const zcashDir = isDev ? `${HOME_DIR}/.zcash/testnet3` : HOME_DIR;
|
||||
const walletDatPath = `${zcashDir}/wallet.dat`;
|
||||
|
||||
const [cannotAccess] = await eres(promisify(fs.access)(walletDatPath));
|
||||
|
||||
/* eslint-disable no-alert */
|
||||
|
||||
if (cannotAccess) {
|
||||
alert(
|
||||
"Couldn't backup the wallet.dat file. You need to back it up manually.",
|
||||
);
|
||||
}
|
||||
|
||||
const [error] = await eres(
|
||||
promisify(fs.copyFile)(walletDatPath, pathToSave),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
alert(
|
||||
"Couldn't backup the wallet.dat file. You need to back it up manually.",
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
viewKeys,
|
||||
privateKeys,
|
||||
importedPrivateKeys,
|
||||
successExportViewKeys,
|
||||
successExportPrivateKeys,
|
||||
successImportPrivateKeys,
|
||||
isLoading,
|
||||
error,
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<ConfirmDialogComponent
|
||||
title='Export view keys'
|
||||
renderTrigger={toggleVisibility => (
|
||||
<Btn label='Export view keys' onClick={toggleVisibility} />
|
||||
)}
|
||||
onConfirm={this.exportViewKeys}
|
||||
showButtons={!successExportViewKeys}
|
||||
width={750}
|
||||
>
|
||||
<ModalContent>
|
||||
{successExportViewKeys ? (
|
||||
viewKeys.map(({ zAddress, key }) => (
|
||||
<>
|
||||
<InputLabelComponent value={zAddress} />
|
||||
<RowComponent alignItems='center'>
|
||||
<InputComponent
|
||||
value={key}
|
||||
onFocus={(event) => {
|
||||
event.currentTarget.select();
|
||||
}}
|
||||
/>
|
||||
<ClipboardButton text={key} />
|
||||
</RowComponent>
|
||||
</>
|
||||
))
|
||||
) : (
|
||||
<TextComponent value='Ut id vulputate arcu. Curabitur mattis aliquam magna sollicitudin vulputate. Morbi tempus bibendum porttitor. Quisque dictum ac ipsum a luctus. Donec et lacus ac erat consectetur molestie a id erat.' />
|
||||
)}
|
||||
</ModalContent>
|
||||
</ConfirmDialogComponent>
|
||||
|
||||
<ConfirmDialogComponent
|
||||
title='Export private keys'
|
||||
renderTrigger={toggleVisibility => (
|
||||
<Btn label='Export private keys' onClick={toggleVisibility} />
|
||||
)}
|
||||
onConfirm={this.exportPrivateKeys}
|
||||
showButtons={!successExportPrivateKeys}
|
||||
width={750}
|
||||
>
|
||||
<ModalContent>
|
||||
{successExportPrivateKeys ? (
|
||||
privateKeys.map(({ zAddress, key }) => (
|
||||
<>
|
||||
<InputLabelComponent value={zAddress} />
|
||||
<RowComponent alignItems='center'>
|
||||
<InputComponent
|
||||
value={key}
|
||||
onFocus={(event) => {
|
||||
event.currentTarget.select();
|
||||
}}
|
||||
/>
|
||||
<ClipboardButton text={key} />
|
||||
</RowComponent>
|
||||
</>
|
||||
))
|
||||
) : (
|
||||
<TextComponent value='Ut id vulputate arcu. Curabitur mattis aliquam magna sollicitudin vulputate. Morbi tempus bibendum porttitor. Quisque dictum ac ipsum a luctus. Donec et lacus ac erat consectetur molestie a id erat.' />
|
||||
)}
|
||||
</ModalContent>
|
||||
</ConfirmDialogComponent>
|
||||
|
||||
<ConfirmDialogComponent
|
||||
title='Import private keys'
|
||||
renderTrigger={toggleVisibility => (
|
||||
<Btn label='Import private keys' onClick={toggleVisibility} />
|
||||
)}
|
||||
onConfirm={this.importPrivateKeys}
|
||||
showButtons={!successImportPrivateKeys}
|
||||
width={900}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
<ModalContent>
|
||||
<InputLabelComponent value='Please paste your private keys here, one per line. The keys will be imported into your zcashd node' />
|
||||
<InputComponent
|
||||
value={importedPrivateKeys}
|
||||
onChange={value => this.setState({ importedPrivateKeys: value })}
|
||||
inputType='textarea'
|
||||
rows={10}
|
||||
/>
|
||||
{successImportPrivateKeys && (
|
||||
<TextComponent
|
||||
value='Private keys imported in your node'
|
||||
align='center'
|
||||
/>
|
||||
)}
|
||||
{error && <TextComponent value={error} align='center' />}
|
||||
</ModalContent>
|
||||
</ConfirmDialogComponent>
|
||||
|
||||
<Btn label='Backup wallet.dat' onClick={this.backupWalletDat} />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ const createWindow = () => {
|
|||
});
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
width: 1000,
|
||||
height: 600,
|
||||
transparent: false,
|
||||
frame: true,
|
||||
|
|
Loading…
Reference in New Issue