Available Dapp selection alignment with Permissions (Portal) (#4374)

* Manage default accounts

* Portal

* Portal

* Allow Portal to be used in as both top-level and popover

* modal/popover variable naming

* Move to Portal

* export Portal in ~/ui

* WIP

* Tags handle empty values

* Export AccountCard in ~/ui

* Allow ETH-only & zero display

* Use ui/Balance for balance display

* Add tests for Balance & Tags component availability

* WIP

* Default overlay display to block (not flex)

* Revert block

* WIP

* Add className, optional handlers only

* WIP

* Properly handle optional onKeyDown

* Selection updated

* Align margins

* Remove old code

* Remove debug logging

* TransitionGroup for animations

* No anim

* Cleanups

* Revert addons removal

* Fix tests

* WIP

* Add onClick to Container

* Create ui/DappCard component

* WIP

* Pass dummy displayApps

* Rename DappsVisible back to AddDapps (easier git diff)

* Rename CSS

* Fix tests after merge
This commit is contained in:
Jaco Greeff 2017-02-02 16:02:45 +01:00 committed by Gav Wood
parent 1547af191b
commit 535ebb1f2f
10 changed files with 190 additions and 125 deletions

View File

@ -15,15 +15,24 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.modal {
flex-direction: column;
}
.container {
margin-top: 1.5em;
overflow-y: auto;
}
.description {
margin-top: .5em !important;
}
.list {
margin-bottom: 1.5em;
.background {
background: rgba(255, 255, 255, 0.2);
margin: 0 -1.5em;
padding: 0.5em 1.5em;
padding: 0.5em 0;
}
.header {
@ -37,3 +46,26 @@
opacity: 0.75;
}
}
.selectIcon {
position: absolute;
right: 0.5em;
top: 0.5em;
}
.selected,
.unselected {
position: relative;
}
.unselected {
background: rgba(0, 0, 0, 0.4) !important;
.selectIcon {
opacity: 0.15;
}
}
.selected {
background: rgba(255, 255, 255, 0.15) !important;
}

View File

@ -14,14 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { Checkbox } from 'material-ui';
import { List, ListItem } from 'material-ui/List';
import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { Modal, Button } from '~/ui';
import { DoneIcon } from '~/ui/Icons';
import { ContainerTitle, DappCard, Portal, SectionList } from '~/ui';
import { CheckIcon } from '~/ui/Icons';
import styles from './addDapps.css';
@ -39,32 +37,23 @@ export default class AddDapps extends Component {
}
return (
<Modal
actions={ [
<Button
icon={ <DoneIcon /> }
key='done'
label={
<FormattedMessage
id='dapps.add.button.done'
defaultMessage='Done'
/>
}
onClick={ store.closeModal }
/>
] }
compact
<Portal
className={ styles.modal }
onClose={ store.closeModal }
open
>
<ContainerTitle
title={
<FormattedMessage
id='dapps.add.label'
defaultMessage='visible applications'
/>
}
visible
>
/>
<div className={ styles.container }>
<div className={ styles.warning } />
{
this.renderList(store.sortedLocal,
this.renderList(store.sortedLocal, store.displayApps,
<FormattedMessage
id='dapps.add.local.label'
defaultMessage='Applications locally available'
@ -76,7 +65,7 @@ export default class AddDapps extends Component {
)
}
{
this.renderList(store.sortedBuiltin,
this.renderList(store.sortedBuiltin, store.displayApps,
<FormattedMessage
id='dapps.add.builtin.label'
defaultMessage='Applications bundled with Parity'
@ -88,7 +77,7 @@ export default class AddDapps extends Component {
)
}
{
this.renderList(store.sortedNetwork,
this.renderList(store.sortedNetwork, store.displayApps,
<FormattedMessage
id='dapps.add.network.label'
defaultMessage='Applications on the global network'
@ -99,11 +88,12 @@ export default class AddDapps extends Component {
/>
)
}
</Modal>
</div>
</Portal>
);
}
renderList (items, header, byline) {
renderList (items, visibleItems, header, byline) {
if (!items || !items.length) {
return null;
}
@ -114,41 +104,40 @@ export default class AddDapps extends Component {
<div className={ styles.header }>{ header }</div>
<div className={ styles.byline }>{ byline }</div>
</div>
<List>
{ items.map(this.renderApp) }
</List>
<SectionList
items={ items }
noStretch
renderItem={ this.renderApp }
/>
</div>
);
}
renderApp = (app) => {
const { store } = this.props;
const isHidden = !store.displayApps[app.id].visible;
const isVisible = store.displayApps[app.id].visible;
const onCheck = () => {
if (isHidden) {
store.showApp(app.id);
} else {
const onClick = () => {
if (isVisible) {
store.hideApp(app.id);
} else {
store.showApp(app.id);
}
};
return (
<ListItem
<DappCard
app={ app }
className={
isVisible
? styles.selected
: styles.unselected
}
key={ app.id }
leftCheckbox={
<Checkbox
checked={ !isHidden }
onCheck={ onCheck }
/>
}
primaryText={ app.name }
secondaryText={
<div className={ styles.description }>
{ app.description }
</div>
}
/>
onClick={ onClick }
>
<CheckIcon className={ styles.selectIcon } />
</DappCard>
);
}
}

View File

@ -33,13 +33,13 @@ describe('modals/AddDapps', () => {
it('does not render the modal with modalOpen = false', () => {
expect(
renderShallow({ modalOpen: false }).find('Connect(Modal)')
renderShallow({ modalOpen: false }).find('Portal')
).to.have.length(0);
});
it('does render the modal with modalOpen = true', () => {
expect(
renderShallow({ modalOpen: true }).find('Connect(Modal)')
renderShallow({ modalOpen: true }).find('Portal')
).to.have.length(1);
});
});

View File

@ -16,10 +16,10 @@
import AddAddress from './AddAddress';
import AddContract from './AddContract';
import AddDapps from './AddDapps';
import CreateAccount from './CreateAccount';
import CreateWallet from './CreateWallet';
import DappPermissions from './DappPermissions';
import DappsVisible from './AddDapps';
import DeleteAccount from './DeleteAccount';
import DeployContract from './DeployContract';
import EditMeta from './EditMeta';
@ -37,10 +37,10 @@ import WalletSettings from './WalletSettings';
export {
AddAddress,
AddContract,
AddDapps,
CreateAccount,
CreateWallet,
DappPermissions,
DappsVisible,
DeleteAccount,
DeployContract,
EditMeta,

View File

@ -29,15 +29,14 @@ export default class Container extends Component {
className: PropTypes.string,
compact: PropTypes.bool,
light: PropTypes.bool,
onClick: PropTypes.func,
style: PropTypes.object,
tabIndex: PropTypes.number,
title: nodeOrStringProptype()
}
render () {
const { children, className, compact, light, style, tabIndex } = this.props;
const classes = `${styles.container} ${light ? styles.light : ''} ${className}`;
const { children, className, compact, light, onClick, style, tabIndex } = this.props;
const props = {};
if (Number.isInteger(tabIndex)) {
@ -45,8 +44,27 @@ export default class Container extends Component {
}
return (
<div className={ classes } style={ style } { ...props }>
<Card className={ compact ? styles.compact : styles.padded }>
<div
className={
[
styles.container,
light
? styles.light
: '',
className
].join(' ')
}
style={ style }
{ ...props }
>
<Card
className={
compact
? styles.compact
: styles.padded
}
onClick={ onClick }
>
{ this.renderTitle() }
{ children }
</Card>

View File

@ -17,59 +17,80 @@
import React, { Component, PropTypes } from 'react';
import { Link } from 'react-router';
import { Container, ContainerTitle, DappIcon, Tags } from '~/ui';
import Container, { Title as ContainerTitle } from '~/ui/Container';
import DappIcon from '~/ui/DappIcon';
import Tags from '~/ui/Tags';
import styles from './summary.css';
import styles from './dappCard.css';
export default class Summary extends Component {
export default class DappCard extends Component {
static propTypes = {
app: PropTypes.object.isRequired,
children: PropTypes.node
}
children: PropTypes.node,
className: PropTypes.string,
onClick: PropTypes.func,
showLink: PropTypes.bool,
showTags: PropTypes.bool
};
static defaultProps = {
showLink: false,
showTags: false
};
render () {
const { app } = this.props;
const { app, children, className, onClick, showLink, showTags } = this.props;
if (!app) {
return null;
}
const link = this.renderLink(app);
return (
<Container className={ styles.container }>
<Container
className={
[styles.container, className].join(' ')
}
onClick={ onClick }
>
<DappIcon
app={ app }
className={ styles.image }
/>
<Tags tags={ [app.type] } />
<Tags
tags={
showTags
? [app.type]
: null
}
/>
<div className={ styles.description }>
<ContainerTitle
className={ styles.title }
title={ link }
title={
showLink
? this.renderLink(app)
: app.name
}
byline={ app.description }
/>
<div className={ styles.author }>
{ app.author }, v{ app.version }
</div>
{ this.props.children }
{ children }
</div>
</Container>
);
}
renderLink (app) {
// Special case for web dapp
if (app.url === 'web') {
return (
<Link to={ `/web` }>
{ app.name }
</Link>
);
<Link
to={
app.url === 'web'
? '/web'
: `/app/${app.id}`
}
return (
<Link to={ `/app/${app.id}` }>
>
{ app.name }
</Link>
);

View File

@ -14,4 +14,4 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './summary';
export default from './dappCard';

View File

@ -30,6 +30,7 @@ import Container, { Title as ContainerTitle } from './Container';
import ContextProvider from './ContextProvider';
import CopyToClipboard from './CopyToClipboard';
import CurrencySymbol from './CurrencySymbol';
import DappCard from './DappCard';
import DappIcon from './DappIcon';
import Editor from './Editor';
import Errors from './Errors';
@ -79,6 +80,7 @@ export {
CopyToClipboard,
CurrencySymbol,
DappIcon,
DappCard,
Editor,
Errors,
FEATURES,

View File

@ -21,14 +21,13 @@ import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { AddDapps, DappPermissions } from '~/modals';
import { DappPermissions, DappsVisible } from '~/modals';
import PermissionStore from '~/modals/DappPermissions/store';
import { Actionbar, Button, Page } from '~/ui';
import { Actionbar, Button, DappCard, Page } from '~/ui';
import { LockedIcon, VisibleIcon } from '~/ui/Icons';
import UrlButton from './UrlButton';
import DappsStore from './dappsStore';
import Summary from './Summary';
import styles from './dapps.css';
@ -82,8 +81,8 @@ class Dapps extends Component {
return (
<div>
<AddDapps store={ this.store } />
<DappPermissions store={ this.permissionStore } />
<DappsVisible store={ this.store } />
<Actionbar
className={ styles.toolbar }
title={
@ -146,7 +145,11 @@ class Dapps extends Component {
className={ styles.item }
key={ app.id }
>
<Summary app={ app } />
<DappCard
app={ app }
showLink
showTags
/>
</div>
);
}