Display requests with Iconbox (#32)

* Display requests with Iconbox

* Make (X) clickable

* Remove cc-test-reporter
This commit is contained in:
Jaco Greeff 2019-05-26 14:56:18 +02:00 committed by GitHub
parent cc5f0f7ea4
commit d8728e473e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 157 additions and 80 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ tmp/
.env.test.local
.env.production.local
.npmrc
cc-test-reporter
lerna-debug.log*
master-build.zip
npm-debug.log*

Binary file not shown.

View File

@ -21,10 +21,9 @@ function Account ({ address, className, onAction }: Props) {
const [isEditing, setEditing] = useState(false);
const [editedname, setName] = useState<string | null>(null);
const toggleEdit = (): void => {
const toggleEdit = () =>
setEditing(!isEditing);
};
const saveChanges = (): void => {
const saveChanges = () => {
if (editedname && editedname !== name) {
editAccount(address, editedname)
.then(() => onAction())

View File

@ -8,7 +8,7 @@ import { OnActionFromCtx } from '../../components/types';
import React from 'react';
import styled from 'styled-components';
import { ActionBar, Box, Button, Link, Tip, defaults, withOnAction } from '../../components';
import { ActionBar, Button, Icon, IconBox, Link, Tip, defaults, withOnAction } from '../../components';
import { approveAuthRequest, rejectAuthRequest } from '../../messaging';
type Props = {
@ -21,19 +21,27 @@ type Props = {
};
function Request ({ authId, className, isFirst, onAction, request: { origin }, url }: Props) {
const onApprove = (): Promise<void> =>
const onApprove = () =>
approveAuthRequest(authId)
.then(() => onAction())
.catch(console.error);
const onReject = (): void => {
const onReject = () =>
rejectAuthRequest(authId)
.then(() => onAction())
.catch(console.error);
};
return (
<Box className={className}>
<div>An application, identified as <div className='tab-name'>{origin}</div> is requesting access from <div className='tab-url'>{url}</div>.</div>
<IconBox
className={className}
icon={
<Icon
icon='X'
onClick={onReject}
/>}
intro={
<div>An application, identified as <div className='tab-name'>{origin}</div> is requesting access from <div className='tab-url'>{url}</div>.</div>
}
>
<ActionBar>
<Link isDanger onClick={onReject}>Reject</Link>
</ActionBar>
@ -44,11 +52,16 @@ function Request ({ authId, className, isFirst, onAction, request: { origin }, u
onClick={onApprove}
/>
)}
</Box>
</IconBox>
);
}
export default withOnAction(styled(Request)`
.icon {
background: ${defaults.btnBgDanger};
color: ${defaults.btnColorDanger};
}
.tab-name,
.tab-url {
color: ${defaults.linkColor};

View File

@ -26,7 +26,7 @@ function Create ({ onAction }: Props) {
}, []);
// FIXME Duplicated between here and Import.tsx
const onCreate = (): void => {
const onCreate = () => {
// this should always be the case
if (name && password && account) {
createAccount(name, password, account.seed)

View File

@ -16,11 +16,10 @@ type Props = RouteComponentProps<{ address: string }> & {
};
function Forget ({ match: { params: { address } }, onAction }: Props) {
const onClick = (): void => {
const onClick = () =>
forgetAccount(address)
.then(() => onAction('/'))
.catch(console.error);
};
return (
<div>

View File

@ -19,18 +19,13 @@ function Import ({ onAction }: Props) {
const [name, setName] = useState<string | null>(null);
const [password, setPassword] = useState<string | null>(null);
const onChangeSeed = (seed: string): void => {
const onChangeSeed = (seed: string) =>
validateSeed(seed)
.then(setAccount)
.catch((error) => {
console.error(error);
setAccount(null);
});
};
.catch(() => setAccount(null));
// FIXME Duplicated between here and Create.tsx
const onCreate = (): void => {
const onCreate = () => {
// this should always be the case
if (name && password && account) {
createAccount(name, password, account.seed)

View File

@ -21,13 +21,13 @@ type Props = {
};
function Request ({ isFirst, onAction, request: { address, genesisHash, method, nonce }, signId, url }: Props) {
const onCancel = (): void => {
const onCancel = () =>
cancelSignRequest(signId)
.then(() => onAction())
.catch(console.error);
};
const onSign = (password: string): Promise<void> =>
approveSignRequest(signId, password).then(() => onAction());
const onSign = (password: string) =>
approveSignRequest(signId, password)
.then(() => onAction());
return (
<Address address={address}>

View File

@ -15,12 +15,9 @@ export default function Unlock ({ className, onSign }: Props) {
const [error, setError] = useState('');
const [password, setPassword] = useState('');
const onClick = (): void => {
onSign(password).catch((error) => {
console.error(error);
setError(error.message);
});
};
const onClick = () =>
onSign(password)
.catch((error) => setError(error.message));
useEffect(() => {
if (error) {

View File

@ -8,74 +8,52 @@ import React from 'react';
import styled from 'styled-components';
import Identicon from '@polkadot/ui-identicon';
import Box from './Box';
import IconBox from './IconBox';
import { withAccounts } from './contexts';
import defaults from './defaults';
type Props = {
accounts: AccountsFromCtx,
address?: string | null,
children?: React.ReactNode;
className?: string,
isHidden?: boolean,
name?: React.ReactNode | null,
theme?: 'polkadot' | 'substrate'
};
function Address ({ accounts, address, children, className, isHidden, name, theme = 'polkadot' }: Props) {
if (isHidden) {
return null;
}
function Address ({ accounts, address, children, className, name, theme = 'polkadot' }: Props) {
const account = accounts.find((account) => account.address === address);
return (
<div className={className}>
<Box className='details'>
<div className='name'>{name || (account && account.meta.name) || '<unknown>'}</div>
<div className='address'>{address || '<unknown>'}</div>
<div className='children'>{children}</div>
</Box>
<Identicon
className='icon'
size={64}
theme={theme}
value={address}
/>
</div>
<IconBox
className={className}
icon={
<Identicon
className='icon'
size={64}
theme={theme}
value={address}
/>
}
intro={
<>
<div className='name'>{name || (account && account.meta.name) || '<unknown>'}</div>
<div className='address'>{address || '<unknown>'}</div>
</>
}
>
{children}
</IconBox>
);
}
export default withAccounts(styled(Address)`
box-sizing: border-box;
margin: ${defaults.boxMargin};
padding: ${defaults.boxPadding};
padding-left: 1rem;
position: relative;
.details {
margin: 0;
.address,
.name {
padding-left: 3rem;
}
.address {
opacity: 0.5;
overflow: hidden;
text-overflow: ellipsis;
}
.name {
padding-bottom: 0.5rem;
}
.address {
opacity: 0.5;
overflow: hidden;
text-overflow: ellipsis;
}
.icon {
left: 0.25rem;
position: absolute;
top: -0.5rem;
z-index: 1;
.name {
padding-bottom: 0.5rem;
}
`);

View File

@ -0,0 +1,35 @@
// Copyright 2019 @polkadot/extension-ui 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 React from 'react';
import styled from 'styled-components';
type Props = {
className?: string,
icon: string,
onClick?: () => any
};
function Icon ({ className, icon, onClick }: Props) {
return (
<div
className={`${className} icon`}
onClick={onClick}
>
{icon}
</div>
);
}
export default styled(Icon)`
background: white;
border-radius: 50%;
box-sizing: border-box;
cursor: ${({ onClick }) =>
onClick
? 'pointer'
: 'inherit'
};
text-align: center;
`;

View File

@ -0,0 +1,58 @@
// Copyright 2019 @polkadot/extension-ui 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 React from 'react';
import styled from 'styled-components';
import Box from './Box';
import defaults from './defaults';
type Props = {
children?: React.ReactNode;
className?: string,
icon: React.ReactNode,
intro: React.ReactNode,
name?: React.ReactNode | null,
theme?: 'polkadot' | 'substrate'
};
function IconBox ({ children, className, icon, intro }: Props) {
return (
<div className={className}>
<Box className='details'>
<div className='intro'>{intro}</div>
<div className='children'>{children}</div>
</Box>
<div className='outer-icon'>{icon}</div>
</div>
);
}
export default styled(IconBox)`
box-sizing: border-box;
margin: ${defaults.boxMargin};
padding: ${defaults.boxPadding};
padding-left: 1rem;
position: relative;
.details {
margin: 0;
.intro {
padding-left: 3rem;
}
}
.outer-icon {
height: 64px;
font-size: 36px;
left: 0.25rem;
line-height: 64px;
position: absolute;
top: -0.5rem;
vertical-align: middle;
width: 64px;
z-index: 1;
}
`;

View File

@ -7,6 +7,8 @@ export { default as Address } from './Address';
export { default as Box } from './Box';
export { default as Button } from './Button';
export { default as Header } from './Header';
export { default as Icon } from './Icon';
export { default as IconBox } from './IconBox';
export { default as Input } from './Input';
export { default as Link } from './Link';
export { default as Loading } from './Loading';