Adjust ErrorBoundary with trigger, cleanup InputAddress outer icon (#2528)

* Adjust ErrorBoundary with trigger, cleanup InputAddress outer icon

* Remove extra fluff
This commit is contained in:
Jaco Greeff 2020-04-07 17:12:04 +02:00 committed by GitHub
parent 94cfc37c29
commit 8fcf2d8864
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 96 deletions

View File

@ -58,7 +58,7 @@ function Content ({ className }: Props): React.ReactElement<Props> {
: (
<>
<Suspense fallback='...'>
<ErrorBoundary>
<ErrorBoundary trigger={name}>
<Component
basePath={`/${name}`}
location={location}

View File

@ -3,94 +3,55 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableExtrinsic } from '@polkadot/api/types';
import { I18nProps } from '@polkadot/react-components/types';
import { ApiProps } from '@polkadot/react-api/types';
import { ComponentProps } from './types';
import { ComponentProps as Props } from './types';
import React from 'react';
import { createType } from '@polkadot/types';
import { Button, Icon, Extrinsic, TxButton, TxComponent } from '@polkadot/react-components';
import { registry } from '@polkadot/react-api';
import { withApi, withMulti } from '@polkadot/react-api/hoc';
import React, { useCallback, useState } from 'react';
import { Button, Icon, Extrinsic, TxButton } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
import translate from './translate';
import { useTranslation } from './translate';
interface Props extends I18nProps, ApiProps, ComponentProps {
onChange: (accountId?: string) => void;
}
function Propose ({ isMine, sudoKey }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { apiDefaultTxSudo } = useApi();
const [method, setMethod] = useState<SubmittableExtrinsic<'promise'> | null>(null);
interface State {
method: SubmittableExtrinsic<'promise'> | null;
isValid: boolean;
}
const _onChangeExtrinsic = useCallback(
(method: SubmittableExtrinsic<'promise'> | null = null) =>
setMethod(() => method),
[]
);
class Propose extends TxComponent<Props, State> {
public state: State = {
isValid: false,
method: null
};
public render (): React.ReactNode {
const { apiDefaultTxSudo, isMine, sudoKey, t } = this.props;
const { isValid, method } = this.state;
return isMine
? (
<section>
<Extrinsic
defaultValue={apiDefaultTxSudo}
label={t('submit the following change')}
onChange={this.onChangeExtrinsic}
onEnter={this.sendTx}
return isMine
? (
<section>
<Extrinsic
defaultValue={apiDefaultTxSudo}
label={t('submit the following change')}
onChange={_onChangeExtrinsic}
/>
<br />
<Button.Group>
<TxButton
accountId={sudoKey}
icon='sign-in'
isDisabled={!method}
label={t('Submit Sudo')}
params={[method]}
tx='sudo.sudo'
withSpinner={false}
/>
<br />
<Button.Group>
<TxButton
accountId={sudoKey}
icon='sign-in'
isDisabled={!method || !isValid}
label={t('Submit Sudo')}
params={method ? [createType(registry, 'Proposal', method)] : []}
tx='sudo.sudo'
withSpinner
/>
</Button.Group>
</section>
)
: (
<article className='error padded'>
<div>
<Icon name='ban' />
{t('You do not have access to the current sudo key')}
</div>
</article>
);
}
private nextState (newState: Partial<State>): void {
this.setState(
(prevState: State): State => {
const { method = prevState.method } = newState;
return {
isValid: !!method,
method
};
}
</Button.Group>
</section>
)
: (
<article className='error padded'>
<div>
<Icon name='ban' />
{t('You do not have access to the current sudo key')}
</div>
</article>
);
}
private onChangeExtrinsic = (method?: SubmittableExtrinsic<'promise'>): void => {
if (!method) {
return;
}
this.nextState({ method });
}
}
export default withMulti(
Propose,
translate,
withApi
);
export default React.memo(Propose);

View File

@ -12,24 +12,31 @@ interface Props extends I18nProps {
children: React.ReactNode;
doThrow?: boolean;
onError?: () => void;
trigger?: any;
}
interface State {
hasError: boolean;
error: Error | null;
prevTrigger: string | null;
}
// NOTE: This is the only way to do an error boundary, via extend
class ErrorBoundary extends React.Component<Props> {
state: State = { hasError: false };
state: State = { error: null, prevTrigger: null };
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static getDerivedStateFromError (_error: Error): State {
// Update state so the next render will show the fallback UI.
return { hasError: true };
static getDerivedStateFromError (error: Error): Partial<State> {
return { error };
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public componentDidCatch (error: Error, _errorInfo: any): void {
static getDerivedStateFromProps ({ trigger }: Props, { prevTrigger }: State): State | null {
const newTrigger = JSON.stringify({ trigger });
return (prevTrigger !== newTrigger)
? { error: null, prevTrigger: newTrigger }
: null;
}
public componentDidCatch (error: Error): void {
const { doThrow, onError } = this.props;
onError && onError();
@ -41,12 +48,16 @@ class ErrorBoundary extends React.Component<Props> {
public render (): React.ReactNode {
const { children, t } = this.props;
const { hasError } = this.state;
const { error } = this.state;
return hasError
return error
? (
<article className='error'>
{t('Uncaught error. Something went wrong with the query and rendering of this component.')}
{t('Uncaught error. Something went wrong with the query and rendering of this component. {{message}}', {
replace: {
message: error.message
}
})}
</article>
)
: children;

View File

@ -60,11 +60,12 @@ function IdentityIcon ({ className, onCopy, prefix, size, theme, value }: Props)
return (
<span
className={className}
className={`ui--IdentityIcon-Outer ${className}`}
data-for={trigger}
data-tip={true}
>
<BaseIdentityIcon
className={className}
isHighlight={isValidator}
onCopy={_onCopy}
prefix={prefix}

View File

@ -290,7 +290,7 @@ const ExportedComponent = withMulti(
.ui.search.selection.dropdown {
> .text > .ui--KeyPair {
.ui--IdentityIcon {
.ui--IdentityIcon-Outer {
border: 1px solid #888;
border-radius: 50%;
left: -2.75rem;