Small init changes (static state) (#663)
* Small init changes (static state) * Hide vanity on empty accounts * Require accounts for apps, cleanup needsApi/needsCalls * Display InputAddress when disable (but no options) * Filter toolbox based on accounts * Accounts gated via app, don't display add * Cleanup linting * Validation display & clear on settings types * Split save for developer & general * Add Reset button to dev settings
This commit is contained in:
parent
15cc5190f0
commit
a8ed300dc4
@ -27,7 +27,7 @@ export default class Transfer extends React.PureComponent<Props> {
|
||||
<section>
|
||||
<h1>transfer</h1>
|
||||
<div className='ui--row'>
|
||||
<article className='medium'>
|
||||
<div className='large'>
|
||||
<InputAddress
|
||||
label='recipient address for this transfer'
|
||||
onChange={this.onChangeRecipient}
|
||||
@ -45,7 +45,7 @@ export default class Transfer extends React.PureComponent<Props> {
|
||||
tx='balances.transfer'
|
||||
/>
|
||||
</Button.Group>
|
||||
</article>
|
||||
</div>
|
||||
<div className='template--summary small'>Make a transfer from any account you control to another account. Transfer fees and per-transaction fees apply and will be calculated upon submission.</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -25,16 +25,10 @@ type State = {
|
||||
};
|
||||
|
||||
class Backup extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isPassValid: false,
|
||||
password: ''
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isPassValid: false,
|
||||
password: ''
|
||||
};
|
||||
|
||||
render () {
|
||||
return (
|
||||
|
||||
@ -26,18 +26,12 @@ type State = {
|
||||
};
|
||||
|
||||
class ChangePass extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isNewValid: false,
|
||||
isOldValid: false,
|
||||
newPass: '',
|
||||
oldPass: ''
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isNewValid: false,
|
||||
isOldValid: false,
|
||||
newPass: '',
|
||||
oldPass: ''
|
||||
};
|
||||
|
||||
render () {
|
||||
return (
|
||||
|
||||
@ -25,18 +25,12 @@ type State = {
|
||||
};
|
||||
|
||||
class Restore extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isFileValid: false,
|
||||
isPassValid: false,
|
||||
json: null,
|
||||
password: ''
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isFileValid: false,
|
||||
isPassValid: false,
|
||||
json: null,
|
||||
password: ''
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t } = this.props;
|
||||
|
||||
@ -27,7 +27,7 @@ type Props = AppProps & I18nProps & {
|
||||
|
||||
type State = {
|
||||
hidden: Array<string>,
|
||||
items: Array<TabItem>
|
||||
tabs: Array<TabItem>
|
||||
};
|
||||
|
||||
class AccountsApp extends React.PureComponent<Props, State> {
|
||||
@ -43,7 +43,7 @@ class AccountsApp extends React.PureComponent<Props, State> {
|
||||
|
||||
this.state = {
|
||||
...baseState,
|
||||
items: [
|
||||
tabs: [
|
||||
{
|
||||
name: 'edit',
|
||||
text: t('Edit account')
|
||||
@ -72,8 +72,10 @@ class AccountsApp extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
static hideEditState () {
|
||||
// Hide vanity as well - since the route order and matching changes, the
|
||||
// /create/:seed route become problematic, so don't allow that option
|
||||
return {
|
||||
hidden: ['edit']
|
||||
hidden: ['edit', 'vanity']
|
||||
};
|
||||
}
|
||||
|
||||
@ -93,7 +95,7 @@ class AccountsApp extends React.PureComponent<Props, State> {
|
||||
|
||||
render () {
|
||||
const { basePath } = this.props;
|
||||
const { hidden, items } = this.state;
|
||||
const { hidden, tabs } = this.state;
|
||||
const renderCreator = this.renderComponent(Creator);
|
||||
|
||||
return (
|
||||
@ -102,7 +104,7 @@ class AccountsApp extends React.PureComponent<Props, State> {
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
hidden={hidden}
|
||||
items={items}
|
||||
items={tabs}
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
@ -122,13 +124,14 @@ class AccountsApp extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderComponent = (Component: React.ComponentType<ComponentProps>) => {
|
||||
private renderComponent (Component: React.ComponentType<ComponentProps>) {
|
||||
return ({ match }: LocationProps) => {
|
||||
const { basePath, onStatusChange } = this.props;
|
||||
const { basePath, location, onStatusChange } = this.props;
|
||||
|
||||
return (
|
||||
<Component
|
||||
basePath={basePath}
|
||||
location={location}
|
||||
match={match}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
|
||||
@ -107,13 +107,14 @@ class AddressesApp extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderComponent = (Component: React.ComponentType<ComponentProps>) => {
|
||||
private renderComponent (Component: React.ComponentType<ComponentProps>) {
|
||||
return () => {
|
||||
const { basePath, onStatusChange } = this.props;
|
||||
const { basePath, location, onStatusChange } = this.props;
|
||||
|
||||
return (
|
||||
<Component
|
||||
basePath={basePath}
|
||||
location={location}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -44,20 +44,14 @@ type State = {
|
||||
};
|
||||
|
||||
class Referendum extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
voteCount: 0,
|
||||
voteCountYay: 0,
|
||||
voteCountNay: 0,
|
||||
votedTotal: new BN(0),
|
||||
votedYay: new BN(0),
|
||||
votedNay: new BN(0)
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
voteCount: 0,
|
||||
voteCountYay: 0,
|
||||
voteCountNay: 0,
|
||||
votedTotal: new BN(0),
|
||||
votedYay: new BN(0),
|
||||
votedNay: new BN(0)
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ democracy_referendumVotesFor }: Props, prevState: State): State | null {
|
||||
if (!democracy_referendumVotesFor) {
|
||||
|
||||
@ -24,14 +24,10 @@ type State = {
|
||||
};
|
||||
|
||||
class EventsRecent extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
prevEventHash: '',
|
||||
recentEvents: []
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
prevEventHash: '',
|
||||
recentEvents: []
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ system_events = [] }: Props, prevState: State): State | null {
|
||||
const prevEventHash = xxhashAsHex(stringToU8a(JSON.stringify(system_events)));
|
||||
|
||||
@ -8,33 +8,17 @@ import { AppProps, I18nProps } from '@polkadot/ui-app/types';
|
||||
import './index.css';
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { QueueConsumer } from '@polkadot/ui-app/Status/Context';
|
||||
import { Tabs } from '@polkadot/ui-app/index';
|
||||
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withMulti, withObservable } from '@polkadot/ui-api/index';
|
||||
|
||||
import Selection from './Selection';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = AppProps & I18nProps & {
|
||||
accountAll?: Array<any>
|
||||
};
|
||||
type Props = AppProps & I18nProps;
|
||||
|
||||
class ExtrinsicsApp extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { accountAll, basePath, t } = this.props;
|
||||
|
||||
if (!accountAll || !Object.keys(accountAll).length) {
|
||||
return (
|
||||
<main className='extrinsics--App'>
|
||||
{t('There are no saved accounts. ')}
|
||||
<Link to='/accounts'>
|
||||
{t('Add Accounts.')}
|
||||
</Link>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
const { basePath, t } = this.props;
|
||||
|
||||
return (
|
||||
<main className='extrinsics--App'>
|
||||
@ -59,8 +43,4 @@ class ExtrinsicsApp extends React.PureComponent<Props> {
|
||||
|
||||
export { ExtrinsicsApp };
|
||||
|
||||
export default withMulti(
|
||||
ExtrinsicsApp,
|
||||
translate,
|
||||
withObservable(accountsObservable.subject, { propName: 'accountAll' })
|
||||
);
|
||||
export default translate(ExtrinsicsApp);
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* of the Apache-2.0 license. See the LICENSE file for details. */
|
||||
|
||||
.sub-label {
|
||||
cursor: pointer;
|
||||
padding: 0rem .5833rem;
|
||||
font-size: .85rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/ui-app/types';
|
||||
import { TabItem } from '@polkadot/ui-app/Tabs';
|
||||
import { SettingsStruct } from '@polkadot/ui-settings/types';
|
||||
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import store from 'store';
|
||||
import typeRegistry from '@polkadot/types/codec/typeRegistry';
|
||||
import { Button, Dropdown, Input, InputFile } from '@polkadot/ui-app/index';
|
||||
import { Button, Dropdown, Input, InputFile, Tabs } from '@polkadot/ui-app/index';
|
||||
import uiSettings from '@polkadot/ui-settings';
|
||||
import { u8aToString } from '@polkadot/util';
|
||||
|
||||
@ -19,130 +21,193 @@ import translate from './translate';
|
||||
type Props = AppProps & I18nProps;
|
||||
|
||||
type State = {
|
||||
settings: SettingsStruct & {
|
||||
types?: { [index: string]: any } | null,
|
||||
typesError?: boolean,
|
||||
typesPlaceholder?: string,
|
||||
customNode: boolean
|
||||
}
|
||||
isCustomNode: boolean,
|
||||
isTypesValid: boolean,
|
||||
isUrlValid: boolean,
|
||||
settings: SettingsStruct,
|
||||
tabs: Array<TabItem>,
|
||||
types?: { [index: string]: any } | null,
|
||||
typesPlaceholder?: string
|
||||
};
|
||||
|
||||
class App extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { t } = props;
|
||||
const types = store.get('types') || {};
|
||||
const names = Object.keys(types);
|
||||
const presets = uiSettings.get();
|
||||
const settings = uiSettings.get();
|
||||
let isCustomNode = true;
|
||||
|
||||
// check to see if user has saved a custom node by seeing if their URL is equal to any preset
|
||||
let customNode = true;
|
||||
for (let i = 0; i < uiSettings.availableNodes.length; i++) {
|
||||
if (uiSettings.availableNodes[i].value === presets.apiUrl) {
|
||||
customNode = false;
|
||||
if (uiSettings.availableNodes[i].value === settings.apiUrl) {
|
||||
isCustomNode = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
settings: {
|
||||
...presets,
|
||||
typesPlaceholder: names.length
|
||||
? names.join(', ')
|
||||
: undefined,
|
||||
customNode: customNode
|
||||
}
|
||||
isCustomNode,
|
||||
isTypesValid: true,
|
||||
isUrlValid: this.isValidUrl(settings.apiUrl),
|
||||
tabs: [
|
||||
{
|
||||
name: 'general',
|
||||
text: t('General')
|
||||
},
|
||||
{
|
||||
name: 'developer',
|
||||
text: t('Developer')
|
||||
}
|
||||
],
|
||||
typesPlaceholder: names.length
|
||||
? names.join(', ')
|
||||
: undefined,
|
||||
settings
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { t } = this.props;
|
||||
const { settings: { apiUrl, i18nLang, typesPlaceholder, typesError, uiMode, uiTheme, customNode } } = this.state;
|
||||
const { basePath } = this.props;
|
||||
const { tabs } = this.state;
|
||||
|
||||
return (
|
||||
<main className='settings--App'>
|
||||
<section>
|
||||
<h1>{t('general')}</h1>
|
||||
<div className='ui--row'>
|
||||
<div className='full'>
|
||||
<div className='sub-label'>
|
||||
{
|
||||
customNode
|
||||
? <><a onClick={this.toggleCustomNode}>{t('pre-set')}</a> | <b>{t('custom')}</b></>
|
||||
: <><b>{t('pre-set')}</b> | <a onClick={this.toggleCustomNode}>{t('custom')}</a></>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
customNode
|
||||
? <Input
|
||||
defaultValue={apiUrl}
|
||||
label={t('remote node/endpoint to connect to')}
|
||||
onChange={this.onChangeApiUrl}
|
||||
/>
|
||||
: <Dropdown
|
||||
defaultValue={apiUrl}
|
||||
label={t('remote node/endpoint to connect to')}
|
||||
onChange={this.onChangeApiUrl}
|
||||
options={uiSettings.availableNodes}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<div className='medium'>
|
||||
<Dropdown
|
||||
defaultValue={uiTheme}
|
||||
label={t('default interface theme')}
|
||||
onChange={this.onChangeUiTheme}
|
||||
options={uiSettings.availableUIThemes}
|
||||
/>
|
||||
</div>
|
||||
<div className='medium'>
|
||||
<Dropdown
|
||||
defaultValue={uiMode}
|
||||
label={t('interface operation mode')}
|
||||
onChange={this.onChangeUiMode}
|
||||
options={uiSettings.availableUIModes}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<div className='full'>
|
||||
<Dropdown
|
||||
defaultValue={i18nLang}
|
||||
isDisabled
|
||||
label={t('default interface language')}
|
||||
onChange={this.onChangeLang}
|
||||
options={uiSettings.availableLanguages}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h1>{t('developer')}</h1>
|
||||
<div className='ui--row'>
|
||||
<div className='full'>
|
||||
<InputFile
|
||||
isError={typesError}
|
||||
label={t('additional type definitions (JSON)')}
|
||||
onChange={this.onChangeTypes}
|
||||
placeholder={typesPlaceholder}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<Button.Group>
|
||||
<Button
|
||||
isPrimary
|
||||
onClick={this.save}
|
||||
label={t('Save & Reload')}
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
items={tabs}
|
||||
/>
|
||||
</Button.Group>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/developer`} render={this.renderDeveloper} />
|
||||
<Route render={this.renderGeneral} />
|
||||
</Switch>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
private renderDeveloper = () => {
|
||||
const { t } = this.props;
|
||||
const { isTypesValid, types, typesPlaceholder } = this.state;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='ui--row'>
|
||||
<div className='full'>
|
||||
<InputFile
|
||||
clearContent={!types && isTypesValid}
|
||||
isError={!isTypesValid}
|
||||
label={t('additional type definitions (JSON)')}
|
||||
onChange={this.onChangeTypes}
|
||||
placeholder={typesPlaceholder}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button.Group>
|
||||
<Button
|
||||
isDisabled={!types}
|
||||
isNegative
|
||||
onClick={this.clearTypes}
|
||||
label={t('Reset')}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
isDisabled={!isTypesValid}
|
||||
isPrimary
|
||||
onClick={this.saveDeveloper}
|
||||
label={t('Save')}
|
||||
/>
|
||||
</Button.Group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private renderGeneral = () => {
|
||||
const { t } = this.props;
|
||||
const { isCustomNode, isUrlValid, settings: { apiUrl, i18nLang, uiMode, uiTheme } } = this.state;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='ui--row'>
|
||||
<div className='full'>
|
||||
<div className='sub-label'>
|
||||
{
|
||||
isCustomNode
|
||||
? <><a onClick={this.toggleCustomNode}>{t('pre-set')}</a> | <b>{t('custom')}</b></>
|
||||
: <><b>{t('pre-set')}</b> | <a onClick={this.toggleCustomNode}>{t('custom')}</a></>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
isCustomNode
|
||||
? <Input
|
||||
defaultValue={apiUrl}
|
||||
isError={!isUrlValid}
|
||||
label={t('remote node/endpoint to connect to')}
|
||||
onChange={this.onChangeApiUrl}
|
||||
/>
|
||||
: <Dropdown
|
||||
defaultValue={apiUrl}
|
||||
label={t('remote node/endpoint to connect to')}
|
||||
onChange={this.onChangeApiUrl}
|
||||
options={uiSettings.availableNodes}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<div className='medium'>
|
||||
<Dropdown
|
||||
defaultValue={uiTheme}
|
||||
label={t('default interface theme')}
|
||||
onChange={this.onChangeUiTheme}
|
||||
options={uiSettings.availableUIThemes}
|
||||
/>
|
||||
</div>
|
||||
<div className='medium'>
|
||||
<Dropdown
|
||||
defaultValue={uiMode}
|
||||
label={t('interface operation mode')}
|
||||
onChange={this.onChangeUiMode}
|
||||
options={uiSettings.availableUIModes}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<div className='full'>
|
||||
<Dropdown
|
||||
defaultValue={i18nLang}
|
||||
isDisabled
|
||||
label={t('default interface language')}
|
||||
onChange={this.onChangeLang}
|
||||
options={uiSettings.availableLanguages}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button.Group>
|
||||
<Button
|
||||
isDisabled={!isUrlValid}
|
||||
isPrimary
|
||||
onClick={this.saveAndReload}
|
||||
label={t('Save & Reload')}
|
||||
/>
|
||||
</Button.Group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private clearTypes = (): void => {
|
||||
this.setState({
|
||||
isTypesValid: true,
|
||||
types: null,
|
||||
typesPlaceholder: ''
|
||||
});
|
||||
}
|
||||
|
||||
private onChangeApiUrl = (apiUrl: string): void => {
|
||||
this.setState(({ settings }: State) => ({
|
||||
isUrlValid: this.isValidUrl(apiUrl),
|
||||
settings: {
|
||||
...settings,
|
||||
apiUrl
|
||||
@ -163,25 +228,19 @@ class App extends React.PureComponent<Props, State> {
|
||||
|
||||
typeRegistry.register(types);
|
||||
|
||||
this.setState(({ settings }: State) => ({
|
||||
settings: {
|
||||
...settings,
|
||||
types,
|
||||
typesError: false,
|
||||
typesPlaceholder
|
||||
}
|
||||
}));
|
||||
this.setState({
|
||||
isTypesValid: true,
|
||||
types,
|
||||
typesPlaceholder
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Registering types:', error);
|
||||
|
||||
this.setState(({ settings }: State) => ({
|
||||
settings: {
|
||||
...settings,
|
||||
types: null,
|
||||
typesError: true,
|
||||
typesPlaceholder: error.message
|
||||
}
|
||||
}));
|
||||
this.setState({
|
||||
isTypesValid: false,
|
||||
types: null,
|
||||
typesPlaceholder: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,49 +263,44 @@ class App extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
private toggleCustomNode = (): void => {
|
||||
this.setState(({ settings }: State) => {
|
||||
const customNode = !settings.customNode;
|
||||
this.setState(({ isCustomNode, settings }: State) => {
|
||||
// reset URL to a preset when toggled to preset
|
||||
const apiUrl = customNode
|
||||
? settings.apiUrl
|
||||
: uiSettings.availableNodes[0].value;
|
||||
const apiUrl = isCustomNode
|
||||
? uiSettings.availableNodes[0].value
|
||||
: settings.apiUrl;
|
||||
|
||||
return {
|
||||
isCustomNode: !isCustomNode,
|
||||
isUrlValid: true,
|
||||
settings: {
|
||||
...settings,
|
||||
apiUrl,
|
||||
customNode
|
||||
apiUrl
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private save = (): void => {
|
||||
const { onStatusChange, t } = this.props;
|
||||
const { settings: { types, typesError } } = this.state;
|
||||
private isValidUrl (apiUrl: string): boolean {
|
||||
return (
|
||||
// some random length... we probably want to parse via some lib
|
||||
(apiUrl.length >= 7) &&
|
||||
// check that it starts with a valid ws identifier
|
||||
(apiUrl.startsWith('ws://') || apiUrl.startsWith('wss://'))
|
||||
);
|
||||
}
|
||||
|
||||
// validate custom node url
|
||||
const apiUrl = this.state.settings.apiUrl;
|
||||
private saveDeveloper = (): void => {
|
||||
const { isTypesValid, types } = this.state;
|
||||
|
||||
if (this.state.settings.customNode) {
|
||||
if (!(apiUrl.startsWith('ws://localhost') ||
|
||||
apiUrl.startsWith('ws://127.0.0.1') ||
|
||||
apiUrl.startsWith('wss://'))) {
|
||||
onStatusChange({
|
||||
action: '',
|
||||
status: 'error',
|
||||
message: t('Custom node URL is not valid')
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uiSettings.set(this.state.settings);
|
||||
|
||||
if (types && !typesError) {
|
||||
if (isTypesValid) {
|
||||
store.set('types', types);
|
||||
}
|
||||
}
|
||||
|
||||
private saveAndReload = (): void => {
|
||||
const { settings } = this.state;
|
||||
|
||||
uiSettings.set(settings);
|
||||
|
||||
// HACK This is terribe, but since the API needs to re-connect, but since
|
||||
// the API does not yet handle re-connections properly, it is what it is
|
||||
|
||||
@ -37,15 +37,11 @@ type State = {
|
||||
};
|
||||
|
||||
class Account extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isNominateOpen: false,
|
||||
isNominating: false,
|
||||
isPrefsOpen: false
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isNominateOpen: false,
|
||||
isNominating: false,
|
||||
isPrefsOpen: false
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ staking_nominating }: Props) {
|
||||
const isNominating = !!staking_nominating && !staking_nominating.isEmpty;
|
||||
|
||||
@ -24,17 +24,11 @@ type State = {
|
||||
};
|
||||
|
||||
class Nominating extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isNomineeValid: false,
|
||||
isAddressFormatValid: false,
|
||||
nominee: ''
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isNomineeValid: false,
|
||||
isAddressFormatValid: false,
|
||||
nominee: ''
|
||||
};
|
||||
|
||||
render () {
|
||||
const { isOpen, style } = this.props;
|
||||
|
||||
@ -86,7 +86,7 @@ class App extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderComponent = (Component: React.ComponentType<ComponentProps>) => {
|
||||
private renderComponent (Component: React.ComponentType<ComponentProps>) {
|
||||
return (): React.ReactNode => {
|
||||
const { intentions, validators } = this.state;
|
||||
const { balances = {} } = this.props;
|
||||
|
||||
@ -20,16 +20,10 @@ type State = {
|
||||
};
|
||||
|
||||
class Raw extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isValid: false,
|
||||
key: new Uint8Array([])
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isValid: false,
|
||||
key: new Uint8Array([])
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t } = this.props;
|
||||
|
||||
@ -65,7 +65,7 @@ class Selection extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderComponent = (Component: React.ComponentType<ComponentProps>) => {
|
||||
private renderComponent (Component: React.ComponentType<ComponentProps>) {
|
||||
return (): React.ReactNode => {
|
||||
return (
|
||||
<Component onAdd={this.onAdd} />
|
||||
|
||||
@ -3,12 +3,15 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/ui-app/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import './index.css';
|
||||
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import Tabs, { TabItem } from '@polkadot/ui-app/Tabs';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withMulti, withObservable } from '@polkadot/ui-api/index';
|
||||
|
||||
import Hash from './Hash';
|
||||
import Rpc from './Rpc';
|
||||
@ -16,7 +19,9 @@ import Sign from './Sign';
|
||||
import Verify from './Verify';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = AppProps & I18nProps;
|
||||
type Props = AppProps & I18nProps & {
|
||||
allAccounts?: SubjectInfo
|
||||
};
|
||||
|
||||
type State = {
|
||||
tabs: Array<TabItem>
|
||||
@ -32,7 +37,7 @@ class ToolboxApp extends React.PureComponent<Props, State> {
|
||||
tabs: [
|
||||
{
|
||||
name: 'rpc',
|
||||
text: 'RPC calls'
|
||||
text: t('RPC calls')
|
||||
},
|
||||
{
|
||||
name: 'hash',
|
||||
@ -50,15 +55,21 @@ class ToolboxApp extends React.PureComponent<Props, State> {
|
||||
};
|
||||
}
|
||||
render () {
|
||||
const { basePath } = this.props;
|
||||
const { allAccounts = {}, basePath } = this.props;
|
||||
const { tabs } = this.state;
|
||||
const hasAccounts = Object.keys(allAccounts).length !== 0;
|
||||
const filteredTabs = hasAccounts
|
||||
? tabs
|
||||
: tabs.filter(({ name }) =>
|
||||
!['sign', 'verify'].includes(name)
|
||||
);
|
||||
|
||||
return (
|
||||
<main className='toolbox--App'>
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
items={tabs}
|
||||
items={filteredTabs}
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
@ -72,4 +83,8 @@ class ToolboxApp extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(ToolboxApp);
|
||||
export default withMulti(
|
||||
ToolboxApp,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
|
||||
@ -31,19 +31,13 @@ type State = {
|
||||
const ZERO = new BN(0);
|
||||
|
||||
class Transfer extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
accountId: null,
|
||||
amount: ZERO,
|
||||
extrinsic: null,
|
||||
hasAvailable: true,
|
||||
recipientId: null
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
accountId: null,
|
||||
amount: ZERO,
|
||||
extrinsic: null,
|
||||
hasAvailable: true,
|
||||
recipientId: null
|
||||
};
|
||||
|
||||
render () {
|
||||
const { t } = this.props;
|
||||
|
||||
@ -3,12 +3,8 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/ui-app/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import React from 'react';
|
||||
import { Trans } from 'react-i18next';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withMulti, withObservable } from '@polkadot/ui-api/index';
|
||||
import { Tabs } from '@polkadot/ui-app/index';
|
||||
|
||||
import './index.css';
|
||||
@ -16,34 +12,14 @@ import './index.css';
|
||||
import Transfer from './Transfer';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = AppProps & I18nProps & {
|
||||
allAccounts?: SubjectInfo
|
||||
};
|
||||
type Props = AppProps & I18nProps;
|
||||
|
||||
class App extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { basePath, t } = this.props;
|
||||
|
||||
return (
|
||||
<main className='transfer--App'>
|
||||
{this.renderBody()}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
private renderBody () {
|
||||
const { allAccounts, basePath, t } = this.props;
|
||||
|
||||
if (!allAccounts || !Object.keys(allAccounts).length) {
|
||||
return (
|
||||
<div className='transfer--App-no-accounts'>
|
||||
<Trans i18nKey='no-accounts'>
|
||||
You currently have no active accounts. Before you are able to transfer, add <a href='#/accounts'>an account</a>.
|
||||
</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
@ -54,13 +30,9 @@ class App extends React.PureComponent<Props> {
|
||||
/>
|
||||
</header>
|
||||
<Transfer />
|
||||
</>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
App,
|
||||
translate,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
export default translate(App);
|
||||
|
||||
@ -23,7 +23,9 @@ type Props = I18nProps & ApiProps & {
|
||||
};
|
||||
|
||||
const unknown = {
|
||||
isApiGated: false,
|
||||
display: {
|
||||
needsApi: undefined
|
||||
},
|
||||
Component: NotFound,
|
||||
name: ''
|
||||
};
|
||||
@ -32,11 +34,11 @@ class Content extends React.Component<Props> {
|
||||
render () {
|
||||
const { isApiConnected, isApiReady, location, t } = this.props;
|
||||
const app = location.pathname.slice(1) || '';
|
||||
const { Component, isApiGated, name } = routing.routes.find((route) =>
|
||||
const { Component, display: { needsApi }, name } = routing.routes.find((route) =>
|
||||
!!(route && app.indexOf(route.name) === 0)
|
||||
) || unknown;
|
||||
|
||||
if (isApiGated && (!isApiReady || !isApiConnected)) {
|
||||
if (needsApi && (!isApiReady || !isApiConnected)) {
|
||||
return (
|
||||
<div className='apps--Content-body'>
|
||||
<main>{t('Waiting for API to be connected and ready.')}</main>
|
||||
@ -51,6 +53,7 @@ class Content extends React.Component<Props> {
|
||||
<Component
|
||||
key='content-content'
|
||||
basePath={`/${name}`}
|
||||
location={location}
|
||||
onStatusChange={queueAction}
|
||||
/>,
|
||||
<Status
|
||||
@ -67,12 +70,12 @@ class Content extends React.Component<Props> {
|
||||
}
|
||||
|
||||
// React-router needs to be first, otherwise we have blocked updates
|
||||
// These API queries are used in a number of places, warm them up as
|
||||
// to avoid constant un/resubscriptions on these
|
||||
export default withMulti(
|
||||
Content,
|
||||
withRouter,
|
||||
translate,
|
||||
// These API queries are used in a number of places, warm them up
|
||||
// to avoid constant un-/re-subscribe on these
|
||||
withCalls<Props>(
|
||||
'query.session.validators',
|
||||
'derive.accounts.indexes',
|
||||
|
||||
@ -4,16 +4,19 @@
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ApiProps } from '@polkadot/ui-api/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { Route } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { withRouter } from 'react-router';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { Icon, Menu } from '@polkadot/ui-app/index';
|
||||
import { withApi, withMulti } from '@polkadot/ui-api/index';
|
||||
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withApi, withMulti, withObservable } from '@polkadot/ui-api/index';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
|
||||
type Props = I18nProps & ApiProps & {
|
||||
allAccounts?: SubjectInfo,
|
||||
route: Route
|
||||
};
|
||||
|
||||
@ -21,7 +24,7 @@ class Item extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { route: { i18n, icon, name }, t } = this.props;
|
||||
|
||||
if (!this.isApiAvailable()) {
|
||||
if (!this.isVisible()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -38,13 +41,18 @@ class Item extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
private isApiAvailable () {
|
||||
const { api, isApiConnected, isApiReady, route: { isApiGated, name, needsApi } } = this.props;
|
||||
private isVisible () {
|
||||
const { allAccounts = {}, api, isApiConnected, isApiReady, route: { display: { isHidden, needsAccounts, needsApi }, name } } = this.props;
|
||||
const hasAccounts = Object.keys(allAccounts).length !== 0;
|
||||
|
||||
if (isApiGated && (!isApiReady || !isApiConnected)) {
|
||||
if (isHidden) {
|
||||
return false;
|
||||
} else if (!needsApi || !needsApi.length) {
|
||||
} else if (needsAccounts && !hasAccounts) {
|
||||
return false;
|
||||
} else if (!needsApi) {
|
||||
return true;
|
||||
} else if (!isApiReady || !isApiConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const notFound = needsApi.filter((endpoint) => {
|
||||
@ -68,5 +76,6 @@ class Item extends React.PureComponent<Props> {
|
||||
export default withMulti(
|
||||
Item,
|
||||
withRouter,
|
||||
withApi
|
||||
withApi,
|
||||
withObservable(accountObservable.subject, { propName: 'allAccounts' })
|
||||
);
|
||||
|
||||
@ -62,26 +62,22 @@ class SideBar extends React.PureComponent<Props> {
|
||||
private renderRoutes () {
|
||||
const { t } = this.props;
|
||||
|
||||
return routing.routes
|
||||
.filter((route) =>
|
||||
!route || !route.isHidden
|
||||
)
|
||||
.map((route, index) => (
|
||||
route
|
||||
? (
|
||||
<Item
|
||||
key={route.name}
|
||||
t={t}
|
||||
route={route}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<Menu.Divider
|
||||
hidden
|
||||
key={index}
|
||||
/>
|
||||
)
|
||||
));
|
||||
return routing.routes.map((route, index) => (
|
||||
route
|
||||
? (
|
||||
<Item
|
||||
key={route.name}
|
||||
t={t}
|
||||
route={route}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<Menu.Divider
|
||||
hidden
|
||||
key={index}
|
||||
/>
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
private renderGithub () {
|
||||
|
||||
@ -9,12 +9,17 @@ import Template from '@polkadot/app-123code/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Template,
|
||||
display: {
|
||||
isHidden: true,
|
||||
needsAccounts: true,
|
||||
needsApi: [
|
||||
'tx.balances.transfer'
|
||||
]
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Template'
|
||||
},
|
||||
icon: 'th',
|
||||
isApiGated: true,
|
||||
isHidden: true,
|
||||
name: '123code'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Accounts from '@polkadot/app-accounts/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Accounts,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Accounts'
|
||||
},
|
||||
icon: 'users',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'accounts'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Addresses from '@polkadot/app-addresses/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Addresses,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Addresses'
|
||||
},
|
||||
icon: 'address book',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'addresses'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,15 +9,16 @@ import Democracy from '@polkadot/app-democracy/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Democracy,
|
||||
display: {
|
||||
needsAccounts: true,
|
||||
needsApi: [
|
||||
'query.democracy.nextTally'
|
||||
]
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Democracy'
|
||||
},
|
||||
icon: 'calendar check',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'democracy',
|
||||
needsApi: [
|
||||
'query.democracy.nextTally'
|
||||
]
|
||||
name: 'democracy'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Explorer from '@polkadot/app-explorer/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Explorer,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Explorer'
|
||||
},
|
||||
icon: 'braille',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'explorer'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,14 @@ import Extrinsics from '@polkadot/app-extrinsics/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Extrinsics,
|
||||
display: {
|
||||
needsAccounts: true,
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Extrinsics'
|
||||
},
|
||||
icon: 'send',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'extrinsics'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Nodeinfo from '@polkadot/app-nodeinfo/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Nodeinfo,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Node info'
|
||||
},
|
||||
icon: 'tty',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'nodeinfo'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Settings from '@polkadot/app-settings/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Settings,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Settings'
|
||||
},
|
||||
icon: 'settings',
|
||||
isApiGated: false,
|
||||
isHidden: false,
|
||||
name: 'settings'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,15 +9,16 @@ import Staking from '@polkadot/app-staking/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Staking,
|
||||
display: {
|
||||
needsAccounts: true,
|
||||
needsApi: [
|
||||
'tx.staking.stake'
|
||||
]
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Staking'
|
||||
},
|
||||
icon: 'certificate',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'staking',
|
||||
needsApi: [
|
||||
'tx.staking.stake'
|
||||
]
|
||||
name: 'staking'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Storage from '@polkadot/app-storage/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Storage,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Chain state'
|
||||
},
|
||||
icon: 'database',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'chainstate'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,13 @@ import Toolbox from '@polkadot/app-toolbox/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Toolbox,
|
||||
display: {
|
||||
needsApi: []
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Toolbox'
|
||||
},
|
||||
icon: 'configure',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'toolbox'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,15 +9,16 @@ import Transfer from '@polkadot/app-transfer/index';
|
||||
export default ([
|
||||
{
|
||||
Component: Transfer,
|
||||
display: {
|
||||
needsAccounts: true,
|
||||
needsApi: [
|
||||
'tx.balances.transfer'
|
||||
]
|
||||
},
|
||||
i18n: {
|
||||
defaultValue: 'Transfer'
|
||||
},
|
||||
icon: 'angle double right',
|
||||
isApiGated: true,
|
||||
isHidden: false,
|
||||
name: 'transfer',
|
||||
needsApi: [
|
||||
'tx.balances.transfer'
|
||||
]
|
||||
name: 'transfer'
|
||||
}
|
||||
] as Routes);
|
||||
|
||||
@ -9,12 +9,14 @@ export type RouteProps = AppProps & BareProps;
|
||||
|
||||
export type Route = {
|
||||
Component: React.ComponentType<RouteProps>,
|
||||
i18n: any, // I18Next$Translate$Config,
|
||||
display: {
|
||||
isHidden?: boolean,
|
||||
needsAccounts?: boolean,
|
||||
needsApi?: Array<string>
|
||||
},
|
||||
i18n: { defaultValue: string },
|
||||
icon: SemanticICONS,
|
||||
isApiGated: boolean,
|
||||
isHidden: boolean,
|
||||
name: string,
|
||||
needsApi?: Array<string>
|
||||
name: string
|
||||
};
|
||||
|
||||
export type Routes = Array<Route | null>;
|
||||
|
||||
@ -26,7 +26,11 @@ const NOOP = () => {
|
||||
export default function withCall<P extends ApiProps> (endpoint: string, { at, atProp, callOnResult, params = [], paramName = 'params', propName, transform = echoTransform }: Options = {}): (Inner: React.ComponentType<ApiProps>) => React.ComponentType<any> {
|
||||
return (Inner: React.ComponentType<ApiProps>): React.ComponentType<Subtract<P, ApiProps>> => {
|
||||
class WithPromise extends React.Component<P, State> {
|
||||
state: State;
|
||||
state: State = {
|
||||
callResult: void 0,
|
||||
callUpdated: false,
|
||||
callUpdatedAt: 0
|
||||
};
|
||||
private destroy?: () => void;
|
||||
private isActive: boolean = false;
|
||||
private propName: string;
|
||||
@ -38,11 +42,6 @@ export default function withCall<P extends ApiProps> (endpoint: string, { at, at
|
||||
const [, section, method] = endpoint.split('.');
|
||||
|
||||
this.propName = `${section}_${method}`;
|
||||
this.state = {
|
||||
callResult: void 0,
|
||||
callUpdated: false,
|
||||
callUpdatedAt: 0
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps: any) {
|
||||
|
||||
@ -23,18 +23,12 @@ type State = CallState & {
|
||||
export default function withObservable<T, P> (observable: Observable<P>, { callOnResult, propName = 'value', transform = echoTransform }: Options = {}): HOC {
|
||||
return (Inner: React.ComponentType<any>, defaultProps: DefaultProps = {}, render?: RenderFn): React.ComponentType<any> => {
|
||||
return class WithObservable extends React.Component<any, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: any) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
callResult: void 0,
|
||||
callUpdated: false,
|
||||
callUpdatedAt: 0,
|
||||
subscriptions: []
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
callResult: void 0,
|
||||
callUpdated: false,
|
||||
callUpdatedAt: 0,
|
||||
subscriptions: []
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.setState({
|
||||
|
||||
@ -76,11 +76,7 @@ const createOption = (address: string) => {
|
||||
};
|
||||
|
||||
class InputAddress extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
state: State = {};
|
||||
|
||||
static getDerivedStateFromProps ({ value }: Props): State | null {
|
||||
try {
|
||||
@ -112,8 +108,9 @@ class InputAddress extends React.PureComponent<Props, State> {
|
||||
render () {
|
||||
const { className, defaultValue, hideAddress = false, isDisabled = false, isError, label, optionsAll, type = DEFAULT_TYPE, style, withLabel } = this.props;
|
||||
const { value } = this.state;
|
||||
const hasOptions = optionsAll && Object.keys(optionsAll[type]).length !== 0;
|
||||
|
||||
if (!optionsAll || !Object.keys(optionsAll[type]).length) {
|
||||
if (!hasOptions && !isDisabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -143,7 +140,7 @@ class InputAddress extends React.PureComponent<Props, State> {
|
||||
options={
|
||||
isDisabled && actualValue
|
||||
? [createOption(actualValue)]
|
||||
: optionsAll[type]
|
||||
: (optionsAll ? optionsAll[type] : [])
|
||||
}
|
||||
style={style}
|
||||
value={value}
|
||||
|
||||
@ -16,6 +16,7 @@ type Props = BareProps & WithNamespaces & {
|
||||
// Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept
|
||||
// i.e. MIME types: 'application/json, text/plain', or '.json, .txt'
|
||||
accept?: string,
|
||||
clearContent?: boolean,
|
||||
isDisabled?: boolean,
|
||||
isError?: boolean,
|
||||
label: string,
|
||||
@ -41,7 +42,7 @@ class InputFile extends React.PureComponent<Props, State> {
|
||||
state: State = {};
|
||||
|
||||
render () {
|
||||
const { accept, className, isDisabled, isError = false, label, placeholder, t, withLabel } = this.props;
|
||||
const { accept, className, clearContent, isDisabled, isError = false, label, placeholder, t, withLabel } = this.props;
|
||||
const { file } = this.state;
|
||||
|
||||
return (
|
||||
@ -58,7 +59,7 @@ class InputFile extends React.PureComponent<Props, State> {
|
||||
>
|
||||
<div className='label'>
|
||||
{
|
||||
!file
|
||||
!file || clearContent
|
||||
? placeholder || t('drag and drop the file here')
|
||||
: placeholder || t('{{name}} ({{size}} bytes)', {
|
||||
replace: file
|
||||
|
||||
@ -45,14 +45,17 @@ class Tabs extends React.PureComponent<Props> {
|
||||
const to = index === 0
|
||||
? basePath
|
||||
: `${basePath}/${name}`;
|
||||
// only do exact matching when not the fallback (first position tab),
|
||||
// params are problematic for dynamic hidden such as app-accounts
|
||||
const isExact = !hasParams || index === 0;
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
activeClassName='active'
|
||||
className='item'
|
||||
exact={!hasParams}
|
||||
exact={isExact}
|
||||
key={to}
|
||||
strict={!hasParams}
|
||||
strict={isExact}
|
||||
to={to}
|
||||
>
|
||||
{text}
|
||||
|
||||
@ -15,6 +15,7 @@ export type BareProps = {
|
||||
|
||||
export type AppProps = {
|
||||
basePath: string,
|
||||
location: Location,
|
||||
onStatusChange: (status: ActionStatus) => void
|
||||
};
|
||||
|
||||
|
||||
@ -16,13 +16,9 @@ type State = {
|
||||
};
|
||||
|
||||
export default class Bytes extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isFileDrop: false
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isFileDrop: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const { isDisabled } = this.props;
|
||||
|
||||
@ -20,16 +20,12 @@ type State = {
|
||||
};
|
||||
|
||||
export default class Tuple extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
Components: [],
|
||||
sub: [],
|
||||
subTypes: [],
|
||||
values: []
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
Components: [],
|
||||
sub: [],
|
||||
subTypes: [],
|
||||
values: []
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ defaultValue: { value }, type: { sub, type } }: Props, prevState: State): Partial<State> | null {
|
||||
if (type === prevState.type) {
|
||||
|
||||
@ -24,14 +24,10 @@ type State = {
|
||||
};
|
||||
|
||||
class Vector extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
Component: null,
|
||||
values: []
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
Component: null,
|
||||
values: []
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ defaultValue: { value = [] }, isDisabled, type: { sub, type } }: Props, prevState: State): Partial<State> | null {
|
||||
if (type === prevState.type) {
|
||||
|
||||
@ -26,16 +26,12 @@ type State = ExtraFees & {
|
||||
};
|
||||
|
||||
class Proposal extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
extraFees: new BN(0),
|
||||
extraAmount: new BN(0),
|
||||
extraWarn: false,
|
||||
isBelowMinimum: false
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
extraFees: new BN(0),
|
||||
extraAmount: new BN(0),
|
||||
extraWarn: false,
|
||||
isBelowMinimum: false
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ deposit, democracy_minimumDeposit = new BN(0), onChange }: Props): State {
|
||||
const extraAmount = deposit instanceof Compact
|
||||
|
||||
@ -30,17 +30,13 @@ type State = ExtraFees & {
|
||||
};
|
||||
|
||||
class Transfer extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
extraFees: new BN(0),
|
||||
extraAmount: new BN(0),
|
||||
extraWarn: false,
|
||||
isCreation: false,
|
||||
isNoEffect: false
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
extraFees: new BN(0),
|
||||
extraAmount: new BN(0),
|
||||
extraWarn: false,
|
||||
isCreation: false,
|
||||
isNoEffect: false
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ amount, balances_votingBalance = ZERO_BALANCE, fees, onChange }: Props): State {
|
||||
let extraFees = fees.transferFee;
|
||||
|
||||
@ -39,16 +39,10 @@ type State = {
|
||||
};
|
||||
|
||||
class Signer extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
password: '',
|
||||
unlockError: null
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
password: '',
|
||||
unlockError: null
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ queue }: Props, { currentItem, password, unlockError }: State): State {
|
||||
const nextItem = queue.find(({ status }) =>
|
||||
|
||||
@ -11,5 +11,6 @@
|
||||
"Transaction": {
|
||||
"inputs": "Vec<TransactionInput>",
|
||||
"outputs": "Vec<TransactionOutput>"
|
||||
}
|
||||
},
|
||||
"blah": "u32"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user