Home landing page (#4178)
* Home entry point (basics) * WIP store for web * Add DappUrlInput component * Updated tests * WIP store update * Adjust styling * Add home tab * Collapse first/last without extra divs * Navigation actually navigates * styling * Encoding of ethlink.io URLs * encodedUrl setup * base58 encoded URLs * Added decoding, updated tests to Parity-compliant * Base32 (synced with Rust implementation via tests) * Split URL into 63 character chunks * Fix store test * Cleanups * s/ethlink/dapplink/ * Display app navigation & histroy * Start on /accounts (for now, until expanded fully) * Update tests * ethlink.io -> web3.site * Basic list layout * Store history on navigation * Show Accounts & Dapps * Add skeleton for DappIcon (WIP) * DappIcon WIP * DappIcon in place * Split into maneable sub-components * WIP * Tests for views/Home * Swap default entry-point to /home * Expose registry.get via lookupMeta * Add getEntry interface, fix instance retrieval (with tests) * Add news display component * Add tests for added contracts/registry methods * Fix GHH test refactoring * render news via SectionList * News items store directly * Images * News & Urls has new layout * Convert remainder * First run-through of MVP for SectionList * Update tests * Deploycontract should not override global p styles * Allow styles overrides for head & body * Adjust layout styling * revert Container>flex * Adjust sizes of history items * Cleanups * HistoryStore for tracking relevant routes * Default route is still /accounts * Fix tests * Update 2015-2017 * Add lookupMeta & tests * Add getEntry & tests * Split Dapp icon into ui/DappIcon * Update copyright dates * Encoding for *.web3.site urls * Dapp history retrieval * Grow to only 40% on hover * Update description * Add DappUrlInput component * Update Web views with store * Update spec description * Update spec description * edited url does not allow in-place store edits * Use /web/<hash> urls for iframe * Removed (now) unused _list.css * Mistamtched merge fixed * Tab split (WIP) * Split Tab component * Update tests after merge * typo * Remove background !important * Set item width to parent * Set width, remove overflow-x: hidden * Align hover overlays * Container defaults to some opacity * Display history from listRecentDapps * Override styles for a tags * Open URLs in new window when extension is available * Fix tests after update * AccountCard width 100% * Re-add opening correct url in tab * Cleanup link rendering * Remove hardcoded news URL * pre-merge * Extra padding at Home bottom (Pr grumble) * Match js-vaults stretch * s/Web Apps via URL/Web Apps/ (PR grumble) * Store recent wallets (PR grumble) * Simplify inline style matching (PR comment) * Add store for new retrieval * Add missing observer * Auto-link based on account type * Fix UI overlaps * Extra spacing * Only show account when accountInfo is available * Align timestamp line-heights * Fix tests * Update tests * Really fix failing test (check for Connect(Account))
This commit is contained in:
parent
78917d728d
commit
63d2cfcbfc
@ -183,6 +183,7 @@
|
|||||||
"react-element-to-jsx-string": "6.0.0",
|
"react-element-to-jsx-string": "6.0.0",
|
||||||
"react-event-listener": "0.4.1",
|
"react-event-listener": "0.4.1",
|
||||||
"react-intl": "2.1.5",
|
"react-intl": "2.1.5",
|
||||||
|
"react-markdown": "2.4.4",
|
||||||
"react-portal": "3.0.0",
|
"react-portal": "3.0.0",
|
||||||
"react-redux": "4.4.6",
|
"react-redux": "4.4.6",
|
||||||
"react-router": "3.0.0",
|
"react-router": "3.0.0",
|
||||||
|
@ -181,6 +181,16 @@ export function outReceipt (receipt) {
|
|||||||
return receipt;
|
return receipt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function outRecentDapps (recentDapps) {
|
||||||
|
if (recentDapps) {
|
||||||
|
Object.keys(recentDapps).forEach((url) => {
|
||||||
|
recentDapps[url] = outDate(recentDapps[url]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return recentDapps;
|
||||||
|
}
|
||||||
|
|
||||||
export function outSignerRequest (request) {
|
export function outSignerRequest (request) {
|
||||||
if (request) {
|
if (request) {
|
||||||
Object.keys(request).forEach((key) => {
|
Object.keys(request).forEach((key) => {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outNumber, outPeer, outPeers, outReceipt, outSyncing, outTransaction, outTrace, outVaultMeta } from './output';
|
import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outNumber, outPeer, outPeers, outReceipt, outRecentDapps, outSyncing, outTransaction, outTrace, outVaultMeta } from './output';
|
||||||
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
||||||
|
|
||||||
describe('api/format/output', () => {
|
describe('api/format/output', () => {
|
||||||
@ -337,6 +337,14 @@ describe('api/format/output', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('outRecentDapps', () => {
|
||||||
|
it('formats the URLs with timestamps', () => {
|
||||||
|
expect(outRecentDapps({ testing: 0x57513668 })).to.deep.equal({
|
||||||
|
testing: new Date('2016-06-03T07:48:56.000Z')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('outSyncing', () => {
|
describe('outSyncing', () => {
|
||||||
['currentBlock', 'highestBlock', 'startingBlock', 'warpChunksAmount', 'warpChunksProcessed'].forEach((input) => {
|
['currentBlock', 'highestBlock', 'startingBlock', 'warpChunksAmount', 'warpChunksProcessed'].forEach((input) => {
|
||||||
it(`formats ${input} numbers as a number`, () => {
|
it(`formats ${input} numbers as a number`, () => {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber } from '../../format/input';
|
import { inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber } from '../../format/input';
|
||||||
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outNumber, outPeers, outTransaction, outVaultMeta } from '../../format/output';
|
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output';
|
||||||
|
|
||||||
export default class Parity {
|
export default class Parity {
|
||||||
constructor (transport) {
|
constructor (transport) {
|
||||||
@ -222,7 +222,8 @@ export default class Parity {
|
|||||||
|
|
||||||
listRecentDapps () {
|
listRecentDapps () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_listRecentDapps');
|
.execute('parity_listRecentDapps')
|
||||||
|
.then(outRecentDapps);
|
||||||
}
|
}
|
||||||
|
|
||||||
listStorageKeys (address, count, hash = null, blockNumber = 'latest') {
|
listStorageKeys (address, count, hash = null, blockNumber = 'latest') {
|
||||||
|
@ -48,6 +48,10 @@ export default {
|
|||||||
label: 'Contracts'
|
label: 'Contracts'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
home: {
|
||||||
|
label: 'Home'
|
||||||
|
},
|
||||||
|
|
||||||
status: {
|
status: {
|
||||||
label: 'Status'
|
label: 'Status'
|
||||||
},
|
},
|
||||||
|
@ -91,7 +91,7 @@ export default class ParametersStep extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={ styles.parameters }>
|
||||||
<p>
|
<p>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='deployContract.parameters.choose'
|
id='deployContract.parameters.choose'
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
padding-left: 3em;
|
padding-left: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
.parameters {
|
||||||
|
p {
|
||||||
color: rgba(255, 255, 255, 0.498039);
|
color: rgba(255, 255, 255, 0.498039);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Accounts, Account, Addresses, Address, Application,
|
Accounts, Account, Addresses, Address, Application,
|
||||||
Contract, Contracts, Dapp, Dapps, HistoryStore,
|
Contract, Contracts, Dapp, Dapps, HistoryStore, Home,
|
||||||
Settings, SettingsBackground, SettingsParity, SettingsProxy,
|
Settings, SettingsBackground, SettingsParity, SettingsProxy,
|
||||||
SettingsViews, Signer, Status,
|
SettingsViews, Signer, Status,
|
||||||
Wallet, Web, WriteContract
|
Wallet, Web, WriteContract
|
||||||
@ -54,10 +54,16 @@ const accountsRoutes = [
|
|||||||
path: ':address',
|
path: ':address',
|
||||||
component: Account,
|
component: Account,
|
||||||
onEnter: ({ params }) => {
|
onEnter: ({ params }) => {
|
||||||
accountsHistory.add(params.address);
|
accountsHistory.add(params.address, 'account');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ path: '/wallet/:address', component: Wallet }
|
{
|
||||||
|
path: '/wallet/:address',
|
||||||
|
component: Wallet,
|
||||||
|
onEnter: ({ params }) => {
|
||||||
|
accountsHistory.add(params.address, 'wallet');
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const addressesRoutes = [
|
const addressesRoutes = [
|
||||||
@ -86,8 +92,8 @@ const routes = [
|
|||||||
{ path: '/address/:address', onEnter: handleDeprecatedRoute },
|
{ path: '/address/:address', onEnter: handleDeprecatedRoute },
|
||||||
{ path: '/contract/:address', onEnter: handleDeprecatedRoute },
|
{ path: '/contract/:address', onEnter: handleDeprecatedRoute },
|
||||||
|
|
||||||
{ path: '/', onEnter: redirectTo('/accounts') },
|
{ path: '/', onEnter: redirectTo('/home') },
|
||||||
{ path: '/auth', onEnter: redirectTo('/accounts') },
|
{ path: '/auth', onEnter: redirectTo('/home') },
|
||||||
{ path: '/settings', onEnter: redirectTo('/settings/views') }
|
{ path: '/settings', onEnter: redirectTo('/settings/views') }
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -127,6 +133,7 @@ const childRoutes = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ path: 'apps', component: Dapps },
|
{ path: 'apps', component: Dapps },
|
||||||
|
{ path: 'home', component: Home },
|
||||||
{ path: 'web', component: Web },
|
{ path: 'web', component: Web },
|
||||||
{ path: 'web/:url', component: Web },
|
{ path: 'web/:url', component: Web },
|
||||||
{ path: 'signer', component: Signer }
|
{ path: 'signer', component: Signer }
|
||||||
|
@ -14,11 +14,37 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$background: rgba(18, 18, 18, 0.85);
|
||||||
|
$backgroundOverlay: rgba(18, 18, 18, 1);
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
background: $background;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0em;
|
|
||||||
background: rgba(0, 0, 0, 0.8);
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
padding: 0em;
|
||||||
|
transition: all 0.75s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.hoverOverlay {
|
||||||
|
background: $backgroundOverlay;
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
margin-top: -1.5em;
|
||||||
|
padding: 0 1.5em 1.5em 1.5em;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $backgroundOverlay;
|
||||||
|
|
||||||
|
.hoverOverlay {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.compact,
|
.compact,
|
||||||
|
@ -28,6 +28,7 @@ export default class Container extends Component {
|
|||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
compact: PropTypes.bool,
|
compact: PropTypes.bool,
|
||||||
|
hover: PropTypes.node,
|
||||||
light: PropTypes.bool,
|
light: PropTypes.bool,
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
@ -68,10 +69,25 @@ export default class Container extends Component {
|
|||||||
{ this.renderTitle() }
|
{ this.renderTitle() }
|
||||||
{ children }
|
{ children }
|
||||||
</Card>
|
</Card>
|
||||||
|
{ this.renderHover() }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderHover () {
|
||||||
|
const { hover } = this.props;
|
||||||
|
|
||||||
|
if (!hover) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={ styles.hoverOverlay }>
|
||||||
|
{ hover }
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderTitle () {
|
renderTitle () {
|
||||||
const { title } = this.props;
|
const { title } = this.props;
|
||||||
|
|
||||||
|
@ -37,10 +37,17 @@ describe('ui/Container', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('sections', () => {
|
describe('sections', () => {
|
||||||
it('renders the Card', () => {
|
it('renders the default Card', () => {
|
||||||
expect(render().find('Card')).to.have.length(1);
|
expect(render().find('Card')).to.have.length(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders Hover Card when available', () => {
|
||||||
|
const cards = render({ hover: <div>testingHover</div> }).find('Card');
|
||||||
|
|
||||||
|
expect(cards).to.have.length(2);
|
||||||
|
expect(cards.get(1).props.children.props.children).to.equal('testingHover');
|
||||||
|
});
|
||||||
|
|
||||||
it('renders the Title', () => {
|
it('renders the Title', () => {
|
||||||
const title = render({ title: 'title' }).find('Title');
|
const title = render({ title: 'title' }).find('Title');
|
||||||
|
|
||||||
|
@ -14,66 +14,33 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import AddIcon from 'material-ui/svg-icons/content/add';
|
export AddIcon from 'material-ui/svg-icons/content/add';
|
||||||
import AttachFileIcon from 'material-ui/svg-icons/editor/attach-file';
|
export AttachFileIcon from 'material-ui/svg-icons/editor/attach-file';
|
||||||
import CancelIcon from 'material-ui/svg-icons/content/clear';
|
export CancelIcon from 'material-ui/svg-icons/content/clear';
|
||||||
import CheckIcon from 'material-ui/svg-icons/navigation/check';
|
export CheckIcon from 'material-ui/svg-icons/navigation/check';
|
||||||
import CloseIcon from 'material-ui/svg-icons/navigation/close';
|
export CloseIcon from 'material-ui/svg-icons/navigation/close';
|
||||||
import CompareIcon from 'material-ui/svg-icons/action/compare-arrows';
|
export CompareIcon from 'material-ui/svg-icons/action/compare-arrows';
|
||||||
import ComputerIcon from 'material-ui/svg-icons/hardware/desktop-mac';
|
export ComputerIcon from 'material-ui/svg-icons/hardware/desktop-mac';
|
||||||
import ContractIcon from 'material-ui/svg-icons/action/code';
|
export ContractIcon from 'material-ui/svg-icons/action/code';
|
||||||
import CopyIcon from 'material-ui/svg-icons/content/content-copy';
|
export CopyIcon from 'material-ui/svg-icons/content/content-copy';
|
||||||
import DashboardIcon from 'material-ui/svg-icons/action/dashboard';
|
export DashboardIcon from 'material-ui/svg-icons/action/dashboard';
|
||||||
import DeleteIcon from 'material-ui/svg-icons/action/delete';
|
export DeleteIcon from 'material-ui/svg-icons/action/delete';
|
||||||
import DoneIcon from 'material-ui/svg-icons/action/done-all';
|
export DoneIcon from 'material-ui/svg-icons/action/done-all';
|
||||||
import EditIcon from 'material-ui/svg-icons/content/create';
|
export EditIcon from 'material-ui/svg-icons/content/create';
|
||||||
import FingerprintIcon from 'material-ui/svg-icons/action/fingerprint';
|
export FingerprintIcon from 'material-ui/svg-icons/action/fingerprint';
|
||||||
import LinkIcon from 'material-ui/svg-icons/content/link';
|
export LinkIcon from 'material-ui/svg-icons/content/link';
|
||||||
import LockedIcon from 'material-ui/svg-icons/action/lock';
|
export LockedIcon from 'material-ui/svg-icons/action/lock';
|
||||||
import MoveIcon from 'material-ui/svg-icons/action/open-with';
|
export MoveIcon from 'material-ui/svg-icons/action/open-with';
|
||||||
import NextIcon from 'material-ui/svg-icons/navigation/arrow-forward';
|
export NextIcon from 'material-ui/svg-icons/navigation/arrow-forward';
|
||||||
import PrevIcon from 'material-ui/svg-icons/navigation/arrow-back';
|
export PrevIcon from 'material-ui/svg-icons/navigation/arrow-back';
|
||||||
import PrintIcon from 'material-ui/svg-icons/action/print';
|
export PrintIcon from 'material-ui/svg-icons/action/print';
|
||||||
import RefreshIcon from 'material-ui/svg-icons/action/autorenew';
|
export RefreshIcon from 'material-ui/svg-icons/action/autorenew';
|
||||||
import SaveIcon from 'material-ui/svg-icons/content/save';
|
export SaveIcon from 'material-ui/svg-icons/content/save';
|
||||||
import SendIcon from 'material-ui/svg-icons/content/send';
|
export SendIcon from 'material-ui/svg-icons/content/send';
|
||||||
import SnoozeIcon from 'material-ui/svg-icons/av/snooze';
|
export SnoozeIcon from 'material-ui/svg-icons/av/snooze';
|
||||||
import StarCircleIcon from 'material-ui/svg-icons/action/stars';
|
export StarCircleIcon from 'material-ui/svg-icons/action/stars';
|
||||||
import StarIcon from 'material-ui/svg-icons/toggle/star';
|
export StarIcon from 'material-ui/svg-icons/toggle/star';
|
||||||
import StarOutlineIcon from 'material-ui/svg-icons/toggle/star-border';
|
export StarOutlineIcon from 'material-ui/svg-icons/toggle/star-border';
|
||||||
import VerifyIcon from 'material-ui/svg-icons/action/verified-user';
|
export VerifyIcon from 'material-ui/svg-icons/action/verified-user';
|
||||||
import VisibleIcon from 'material-ui/svg-icons/image/remove-red-eye';
|
export VisibleIcon from 'material-ui/svg-icons/image/remove-red-eye';
|
||||||
import VpnIcon from 'material-ui/svg-icons/notification/vpn-lock';
|
export VpnIcon from 'material-ui/svg-icons/notification/vpn-lock';
|
||||||
|
|
||||||
export {
|
|
||||||
AddIcon,
|
|
||||||
AttachFileIcon,
|
|
||||||
CancelIcon,
|
|
||||||
CheckIcon,
|
|
||||||
CloseIcon,
|
|
||||||
CompareIcon,
|
|
||||||
ComputerIcon,
|
|
||||||
ContractIcon,
|
|
||||||
CopyIcon,
|
|
||||||
DashboardIcon,
|
|
||||||
DeleteIcon,
|
|
||||||
DoneIcon,
|
|
||||||
EditIcon,
|
|
||||||
FingerprintIcon,
|
|
||||||
LinkIcon,
|
|
||||||
LockedIcon,
|
|
||||||
MoveIcon,
|
|
||||||
NextIcon,
|
|
||||||
PrevIcon,
|
|
||||||
PrintIcon,
|
|
||||||
RefreshIcon,
|
|
||||||
SaveIcon,
|
|
||||||
SendIcon,
|
|
||||||
SnoozeIcon,
|
|
||||||
StarIcon,
|
|
||||||
StarCircleIcon,
|
|
||||||
StarOutlineIcon,
|
|
||||||
VerifyIcon,
|
|
||||||
VisibleIcon,
|
|
||||||
VpnIcon
|
|
||||||
};
|
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.section {
|
.section {
|
||||||
overflow-x: hidden;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
.overlay {
|
.overlay {
|
||||||
background: rgba(0, 0, 0, 0.85);
|
background: rgba(0, 0, 0, 0.85);
|
||||||
@ -33,7 +33,6 @@
|
|||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
/* TODO: As per JS comments, the flex-base could be adjusted in the future to allow for */
|
/* TODO: As per JS comments, the flex-base could be adjusted in the future to allow for */
|
||||||
/* case where <> 3 columns are required should the need arrise from a UI pov. */
|
/* case where <> 3 columns are required should the need arrise from a UI pov. */
|
||||||
@ -42,38 +41,28 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 1 33.33%;
|
flex: 0 1 33.33%;
|
||||||
opacity: 0.75;
|
max-width: 33.33%;
|
||||||
overflow-x: hidden;
|
opacity: 0.85;
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
transition: all 0.75s cubic-bezier(0.23, 1, 0.32, 1);
|
transition: all 0.75s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
|
||||||
/* TODO: The hover and no-hover states can be improved to not "just appear" */
|
|
||||||
&:not(:hover) {
|
|
||||||
& [data-hover="hide"] {
|
|
||||||
}
|
|
||||||
|
|
||||||
& [data-hover="show"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
& [data-hover="hide"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
& [data-hover="show"] {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.stretch-on:hover {
|
&:hover {
|
||||||
flex: 0 0 50%;
|
.item {
|
||||||
}
|
&.stretchOn {
|
||||||
|
flex: 0 1 29%;
|
||||||
|
max-width: 29%;
|
||||||
|
|
||||||
&.stretch-off:hover {
|
&:hover {
|
||||||
|
flex: 0 0 42%;
|
||||||
|
max-width: 42%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,29 +74,34 @@ export default class SectionList extends Component {
|
|||||||
className={ styles.row }
|
className={ styles.row }
|
||||||
key={ `row_${index}` }
|
key={ `row_${index}` }
|
||||||
>
|
>
|
||||||
{ row.map(this.renderItem) }
|
{
|
||||||
|
row
|
||||||
|
.map(this.renderItem)
|
||||||
|
.filter((item) => item)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItem = (item, index) => {
|
renderItem = (item, index) => {
|
||||||
const { noStretch, renderItem } = this.props;
|
const { noStretch, renderItem } = this.props;
|
||||||
|
const itemRendered = renderItem(item, index);
|
||||||
|
|
||||||
|
if (!itemRendered) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Any children that is to be showed or hidden (depending on hover state)
|
|
||||||
// should have the data-hover="show|hide" attributes. For the current implementation
|
|
||||||
// this does the trick, however there may be a case for adding a hover attribute
|
|
||||||
// to an item (mouseEnter/mouseLeave events) and then adjusting the styling with
|
|
||||||
// :root[hover]/:root:not[hover] for the tragetted elements. Currently it is a
|
|
||||||
// CSS-only solution to let the browser do all the work via selectors.
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={ [
|
className={ [
|
||||||
styles.item,
|
styles.item,
|
||||||
styles[`stretch-${noStretch ? 'off' : 'on'}`]
|
noStretch
|
||||||
|
? styles.stretchOff
|
||||||
|
: styles.stretchOn
|
||||||
].join(' ') }
|
].join(' ') }
|
||||||
key={ `item_${index}` }
|
key={ `item_${index}` }
|
||||||
>
|
>
|
||||||
{ renderItem(item, index) }
|
{ itemRendered }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ let instance;
|
|||||||
let renderItem;
|
let renderItem;
|
||||||
|
|
||||||
function render (props = {}) {
|
function render (props = {}) {
|
||||||
renderItem = sinon.stub();
|
renderItem = sinon.stub().returns('someThing');
|
||||||
component = shallow(
|
component = shallow(
|
||||||
<SectionList
|
<SectionList
|
||||||
className='testClass'
|
className='testClass'
|
||||||
|
@ -23,7 +23,7 @@ const lightTheme = getMuiTheme(lightBaseTheme);
|
|||||||
const muiTheme = getMuiTheme(darkBaseTheme);
|
const muiTheme = getMuiTheme(darkBaseTheme);
|
||||||
|
|
||||||
muiTheme.inkBar.backgroundColor = 'transparent';
|
muiTheme.inkBar.backgroundColor = 'transparent';
|
||||||
muiTheme.paper.backgroundColor = 'rgba(0, 0, 0, 0.95)';
|
muiTheme.paper.backgroundColor = 'rgb(18, 18, 18)';
|
||||||
muiTheme.raisedButton.primaryTextColor = 'white';
|
muiTheme.raisedButton.primaryTextColor = 'white';
|
||||||
muiTheme.snackbar.backgroundColor = 'rgba(255, 30, 30, 0.9)';
|
muiTheme.snackbar.backgroundColor = 'rgba(255, 30, 30, 0.9)';
|
||||||
muiTheme.snackbar.textColor = 'rgba(255, 255, 255, 0.75)';
|
muiTheme.snackbar.textColor = 'rgba(255, 255, 255, 0.75)';
|
||||||
|
@ -14,32 +14,33 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
flex: 0 1 50%;
|
|
||||||
width: 50%;
|
|
||||||
position: relative;
|
|
||||||
padding-bottom: 0.25em;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
flex: 0 1 50%;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
position: relative;
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
.item:nth-child(odd) {
|
&:nth-child(odd) {
|
||||||
padding-right: 0.125em;
|
padding-right: 0.125em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item:nth-child(even) {
|
&:nth-child(even) {
|
||||||
padding-left: 0.125em;
|
padding-left: 0.125em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty {
|
.empty {
|
||||||
width: 100%;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
width: 100%;
|
||||||
|
|
||||||
.empty div {
|
div {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,11 @@ export default class Summary extends Component {
|
|||||||
const viewLink = `/${baseLink}/${address}`;
|
const viewLink = `/${baseLink}/${address}`;
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<IdentityName address={ address } name={ name } unknown />
|
<IdentityName
|
||||||
|
address={ address }
|
||||||
|
name={ name }
|
||||||
|
unknown
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (noLink) {
|
if (noLink) {
|
||||||
|
@ -26,7 +26,7 @@ import styles from './extension.css';
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export default class Extension extends Component {
|
export default class Extension extends Component {
|
||||||
store = new Store();
|
store = Store.get();
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { showWarning } = this.store;
|
const { showWarning } = this.store;
|
||||||
|
@ -29,7 +29,10 @@ const NEXT_DISPLAY = '_parity::extensionWarning::nextDisplay';
|
|||||||
// 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig';
|
// 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig';
|
||||||
const EXTENSION_PAGE = 'https://chrome.google.com/webstore/detail/himekenlppkgeaoeddcliojfddemadig';
|
const EXTENSION_PAGE = 'https://chrome.google.com/webstore/detail/himekenlppkgeaoeddcliojfddemadig';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
export default class Store {
|
export default class Store {
|
||||||
|
@observable hasExtension = false;
|
||||||
@observable isInstalling = false;
|
@observable isInstalling = false;
|
||||||
@observable nextDisplay = 0;
|
@observable nextDisplay = 0;
|
||||||
@observable shouldInstall = false;
|
@observable shouldInstall = false;
|
||||||
@ -43,6 +46,10 @@ export default class Store {
|
|||||||
return !this.isInstalling && this.shouldInstall && (Date.now() > this.nextDisplay);
|
return !this.isInstalling && this.shouldInstall && (Date.now() > this.nextDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action setExtensionActive = () => {
|
||||||
|
this.hasExtension = true;
|
||||||
|
}
|
||||||
|
|
||||||
@action setInstalling = (isInstalling) => {
|
@action setInstalling = (isInstalling) => {
|
||||||
this.isInstalling = isInstalling;
|
this.isInstalling = isInstalling;
|
||||||
}
|
}
|
||||||
@ -61,6 +68,7 @@ export default class Store {
|
|||||||
const ua = browser.analyze(navigator.userAgent || '');
|
const ua = browser.analyze(navigator.userAgent || '');
|
||||||
|
|
||||||
if (hasExtension) {
|
if (hasExtension) {
|
||||||
|
this.setExtensionActive();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,4 +105,12 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new Store();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
height: 72px !important;
|
height: 72px !important;
|
||||||
@ -53,7 +54,7 @@
|
|||||||
|
|
||||||
.tabLink,
|
.tabLink,
|
||||||
.settings,
|
.settings,
|
||||||
.logo,
|
.first,
|
||||||
.last {
|
.last {
|
||||||
background: rgba(0, 0, 0, 0.5) !important; /* rgba(0, 0, 0, 0.25) !important; */
|
background: rgba(0, 0, 0, 0.5) !important; /* rgba(0, 0, 0, 0.25) !important; */
|
||||||
}
|
}
|
||||||
@ -73,27 +74,17 @@
|
|||||||
right: -12px;
|
right: -12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.first,
|
||||||
margin: 0 0 0 -24px;
|
|
||||||
padding: 20px 24px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo img {
|
|
||||||
height: 28px;
|
|
||||||
margin-right: 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo div {
|
|
||||||
display: inline-block;
|
|
||||||
text-transform: uppercase;
|
|
||||||
line-height: 32px;
|
|
||||||
vertical-align: top;
|
|
||||||
letter-spacing: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.last {
|
.last {
|
||||||
margin: 0 -24px 0 0;
|
margin: 0;
|
||||||
padding: 36px 12px;
|
padding: 36px 12px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.first {
|
||||||
|
margin-left: -24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.last {
|
||||||
|
margin-right: -24px;
|
||||||
|
}
|
||||||
|
@ -20,13 +20,16 @@ import { Link } from 'react-router';
|
|||||||
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
|
|
||||||
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
|
|
||||||
import { Tooltip } from '~/ui';
|
import { Tooltip } from '~/ui';
|
||||||
|
|
||||||
import Tab from './Tab';
|
import Tab from './Tab';
|
||||||
import styles from './tabBar.css';
|
import styles from './tabBar.css';
|
||||||
|
|
||||||
class TabBar extends Component {
|
class TabBar extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
router: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
isTest: PropTypes.bool,
|
isTest: PropTypes.bool,
|
||||||
netChain: PropTypes.string,
|
netChain: PropTypes.string,
|
||||||
@ -41,41 +44,23 @@ class TabBar extends Component {
|
|||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<Toolbar className={ styles.toolbar }>
|
<Toolbar className={ styles.toolbar }>
|
||||||
{ this.renderLogo() }
|
<ToolbarGroup className={ styles.first }>
|
||||||
{ this.renderTabs() }
|
<div />
|
||||||
{ this.renderLast() }
|
</ToolbarGroup>
|
||||||
|
<div className={ styles.tabs }>
|
||||||
|
{ this.renderTabItems() }
|
||||||
|
</div>
|
||||||
|
<ToolbarGroup className={ styles.last }>
|
||||||
|
<div />
|
||||||
|
</ToolbarGroup>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLogo () {
|
renderTabItems () {
|
||||||
return (
|
|
||||||
<ToolbarGroup>
|
|
||||||
<div className={ styles.logo }>
|
|
||||||
<img
|
|
||||||
height={ 28 }
|
|
||||||
src={ imagesEthcoreBlock }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ToolbarGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLast () {
|
|
||||||
return (
|
|
||||||
<ToolbarGroup>
|
|
||||||
<div className={ styles.last }>
|
|
||||||
<div />
|
|
||||||
</div>
|
|
||||||
</ToolbarGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTabs () {
|
|
||||||
const { views, pending } = this.props;
|
const { views, pending } = this.props;
|
||||||
|
|
||||||
const items = views
|
return views.map((view, index) => {
|
||||||
.map((view, index) => {
|
|
||||||
const body = (view.id === 'accounts')
|
const body = (view.id === 'accounts')
|
||||||
? (
|
? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -101,12 +86,6 @@ class TabBar extends Component {
|
|||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={ styles.tabs }>
|
|
||||||
{ items }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import { withRouter } from 'react-router';
|
|
||||||
|
|
||||||
import Button from '~/ui/Button';
|
|
||||||
import { LinkIcon } from '~/ui/Icons';
|
|
||||||
import Input from '~/ui/Form/Input';
|
|
||||||
|
|
||||||
import styles from './urlButton.css';
|
|
||||||
|
|
||||||
const INPUT_STYLE = { display: 'inline-block', width: '20em' };
|
|
||||||
|
|
||||||
class UrlButton extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
router: PropTypes.object.isRequired // injected by withRouter
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
inputShown: false
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { inputShown } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{ inputShown ? this.renderInput() : null }
|
|
||||||
<Button
|
|
||||||
className={ styles.button }
|
|
||||||
icon={ <LinkIcon /> }
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id='dapps.button.url.label'
|
|
||||||
defaultMessage='URL'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onClick={ this.toggleInput }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderInput () {
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
hint={
|
|
||||||
<FormattedMessage
|
|
||||||
id='dapps.button.url.input'
|
|
||||||
defaultMessage='https://mkr.market'
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onBlur={ this.hideInput }
|
|
||||||
onFocus={ this.showInput }
|
|
||||||
onSubmit={ this.inputOnSubmit }
|
|
||||||
style={ INPUT_STYLE }
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleInput = () => {
|
|
||||||
const { inputShown } = this.state;
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
inputShown: !inputShown
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hideInput = () => {
|
|
||||||
this.setState({ inputShown: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
showInput = () => {
|
|
||||||
this.setState({ inputShown: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
inputOnSubmit = (url) => {
|
|
||||||
const { router } = this.props;
|
|
||||||
|
|
||||||
router.push(`/web/${encodeURIComponent(url)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withRouter(UrlButton);
|
|
@ -19,18 +19,20 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: -0.125em;
|
margin: -0.125em;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 0 1 50%;
|
||||||
|
opacity: 0.85;
|
||||||
|
padding: 0.125em;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.list+.list {
|
.list+.list {
|
||||||
margin-top: -0.25em;
|
margin-top: -0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
padding: 0.125em;
|
|
||||||
flex: 0 1 50%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overlay {
|
.overlay {
|
||||||
background: rgba(0, 0, 0, 0.85);
|
background: rgba(0, 0, 0, 0.85);
|
||||||
bottom: 0.5em;
|
bottom: 0.5em;
|
||||||
|
@ -26,7 +26,6 @@ import PermissionStore from '~/modals/DappPermissions/store';
|
|||||||
import { Actionbar, Button, DappCard, Page } from '~/ui';
|
import { Actionbar, Button, DappCard, Page } from '~/ui';
|
||||||
import { LockedIcon, VisibleIcon } from '~/ui/Icons';
|
import { LockedIcon, VisibleIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
import UrlButton from './UrlButton';
|
|
||||||
import DappsStore from './dappsStore';
|
import DappsStore from './dappsStore';
|
||||||
|
|
||||||
import styles from './dapps.css';
|
import styles from './dapps.css';
|
||||||
@ -92,7 +91,6 @@ class Dapps extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
buttons={ [
|
buttons={ [
|
||||||
<UrlButton key='url' />,
|
|
||||||
<Button
|
<Button
|
||||||
icon={ <VisibleIcon /> }
|
icon={ <VisibleIcon /> }
|
||||||
key='edit'
|
key='edit'
|
||||||
|
50
js/src/views/Home/Accounts/accounts.css
Normal file
50
js/src/views/Home/Accounts/accounts.css
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.accounts {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.account {
|
||||||
|
position: relative;
|
||||||
|
line-height: 2em;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link, .name {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timestamp {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding-top: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
139
js/src/views/Home/Accounts/accounts.js
Normal file
139
js/src/views/Home/Accounts/accounts.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import moment from 'moment';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
|
import { Container, ContainerTitle, IdentityName, IdentityIcon, SectionList } from '~/ui';
|
||||||
|
import { arrayOrObjectProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
|
import styles from './accounts.css';
|
||||||
|
|
||||||
|
class Accounts extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
accountsInfo: PropTypes.object,
|
||||||
|
history: arrayOrObjectProptype().isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className={ styles.accounts }>
|
||||||
|
<ContainerTitle
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.accounts.title'
|
||||||
|
defaultMessage='Recent Accounts'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{ this.renderHistory() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHistory () {
|
||||||
|
const { accountsInfo, history } = this.props;
|
||||||
|
|
||||||
|
if (!accountsInfo || !Object.keys(accountsInfo).length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!history.length) {
|
||||||
|
return (
|
||||||
|
<div className={ styles.empty }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.accounts.none'
|
||||||
|
defaultMessage='No recent accounts history available'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionList
|
||||||
|
items={ history }
|
||||||
|
renderItem={ this.renderHistoryItem }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHistoryItem = (history) => {
|
||||||
|
const { accountsInfo } = this.props;
|
||||||
|
|
||||||
|
if (!history || !history.entry) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = accountsInfo[history.entry] || { meta: {} };
|
||||||
|
let linkType = 'addresses';
|
||||||
|
|
||||||
|
if (account.uuid) {
|
||||||
|
linkType = 'accounts';
|
||||||
|
} else if (account.meta.wallet) {
|
||||||
|
linkType = 'wallet';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
className={ styles.account }
|
||||||
|
key={ history.timestamp }
|
||||||
|
hover={
|
||||||
|
<div className={ styles.timestamp }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.account.visited'
|
||||||
|
defaultMessage='accessed {when}'
|
||||||
|
values={ {
|
||||||
|
when: moment(history.timestamp).fromNow()
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
className={ styles.link }
|
||||||
|
to={ `/${linkType}/${history.entry}` }
|
||||||
|
>
|
||||||
|
<IdentityIcon
|
||||||
|
address={ history.entry }
|
||||||
|
className={ styles.icon }
|
||||||
|
center
|
||||||
|
/>
|
||||||
|
<IdentityName
|
||||||
|
address={ history.entry }
|
||||||
|
className={ styles.name }
|
||||||
|
unknown
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
const { accountsInfo } = state.personal;
|
||||||
|
|
||||||
|
return {
|
||||||
|
accountsInfo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
null
|
||||||
|
)(Accounts);
|
71
js/src/views/Home/Accounts/accounts.spec.js
Normal file
71
js/src/views/Home/Accounts/accounts.spec.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import Accounts from './';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let store;
|
||||||
|
|
||||||
|
function createRedux () {
|
||||||
|
store = {
|
||||||
|
dispatch: sinon.stub(),
|
||||||
|
subscribe: sinon.stub(),
|
||||||
|
getState: () => {
|
||||||
|
return {
|
||||||
|
personal: {
|
||||||
|
accountsInfo: { '0x123': {} }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render (history = []) {
|
||||||
|
component = shallow(
|
||||||
|
<Accounts
|
||||||
|
history={ history }
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
store: createRedux()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).find('Accounts').shallow();
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home/Accounts', () => {
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(render()).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('no history', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders empty message', () => {
|
||||||
|
expect(component.find('FormattedMessage').props().id).to.equal('home.accounts.none');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './urlButton';
|
export default from './accounts';
|
89
js/src/views/Home/Dapps/dapp.js
Normal file
89
js/src/views/Home/Dapps/dapp.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import moment from 'moment';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
|
import { Container, DappIcon } from '~/ui';
|
||||||
|
|
||||||
|
import styles from './dapps.css';
|
||||||
|
|
||||||
|
export default class Dapp extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
store: PropTypes.object.isRequired,
|
||||||
|
timestamp: PropTypes.number.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
dapp: null
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
return this.loadApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { id, timestamp } = this.props;
|
||||||
|
const { dapp } = this.state;
|
||||||
|
|
||||||
|
if (!dapp) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
className={ styles.dapp }
|
||||||
|
hover={
|
||||||
|
<div className={ styles.timestamp }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.dapp.visited'
|
||||||
|
defaultMessage='accessed {when}'
|
||||||
|
values={ {
|
||||||
|
when: moment(timestamp).fromNow()
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
className={ styles.link }
|
||||||
|
to={ `/app/${id}` }
|
||||||
|
>
|
||||||
|
<DappIcon
|
||||||
|
app={ dapp }
|
||||||
|
className={ styles.icon }
|
||||||
|
/>
|
||||||
|
<span className={ styles.name }>
|
||||||
|
{ dapp.name }
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadApp = () => {
|
||||||
|
const { id, store } = this.props;
|
||||||
|
|
||||||
|
return store
|
||||||
|
.loadApp(id)
|
||||||
|
.then((dapp) => {
|
||||||
|
this.setState({ dapp });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
55
js/src/views/Home/Dapps/dapp.spec.js
Normal file
55
js/src/views/Home/Dapps/dapp.spec.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Dapp from './dapp';
|
||||||
|
|
||||||
|
import { createStore } from './dapps.test.js';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let instance;
|
||||||
|
let store;
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
store = createStore();
|
||||||
|
component = shallow(
|
||||||
|
<Dapp
|
||||||
|
id='testId'
|
||||||
|
store={ store }
|
||||||
|
timestamp={ Date.now() }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
instance = component.instance();
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home/Dapp', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
render();
|
||||||
|
return instance.componentWillMount();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(component).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads the dapp on mount', () => {
|
||||||
|
expect(store.loadApp).to.have.been.calledWith('testId');
|
||||||
|
});
|
||||||
|
});
|
48
js/src/views/Home/Dapps/dapps.css
Normal file
48
js/src/views/Home/Dapps/dapps.css
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.dapps {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.dapp {
|
||||||
|
position: relative;
|
||||||
|
line-height: 2em;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link, .name {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timestamp {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
js/src/views/Home/Dapps/dapps.js
Normal file
86
js/src/views/Home/Dapps/dapps.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { ContainerTitle, SectionList } from '~/ui';
|
||||||
|
import { arrayOrObjectProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
|
import Dapp from './dapp';
|
||||||
|
import styles from './dapps.css';
|
||||||
|
|
||||||
|
export default class Dapps extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
history: arrayOrObjectProptype().isRequired,
|
||||||
|
store: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className={ styles.dapps }>
|
||||||
|
<ContainerTitle
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.dapps.title'
|
||||||
|
defaultMessage='Recent Dapps'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{ this.renderHistory() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHistory () {
|
||||||
|
const { history } = this.props;
|
||||||
|
|
||||||
|
if (!history.length) {
|
||||||
|
return (
|
||||||
|
<div className={ styles.empty }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.dapps.none'
|
||||||
|
defaultMessage='No recent Applications history available'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionList
|
||||||
|
items={ history }
|
||||||
|
renderItem={ this.renderHistoryItem }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHistoryItem = (history) => {
|
||||||
|
if (!history || !history.entry) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { store } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dapp
|
||||||
|
id={ history.entry }
|
||||||
|
key={ history.timestamp }
|
||||||
|
store={ store }
|
||||||
|
timestamp={ history.timestamp }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
68
js/src/views/Home/Dapps/dapps.spec.js
Normal file
68
js/src/views/Home/Dapps/dapps.spec.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Dapps from './';
|
||||||
|
|
||||||
|
import { createStore } from './dapps.test.js';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let store;
|
||||||
|
|
||||||
|
function render (history = []) {
|
||||||
|
store = createStore();
|
||||||
|
component = shallow(
|
||||||
|
<Dapps
|
||||||
|
history={ history }
|
||||||
|
store={ store }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home/Dapps', () => {
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(render()).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('no history', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders empty message', () => {
|
||||||
|
expect(component.find('FormattedMessage').props().id).to.equal('home.dapps.none');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with history', () => {
|
||||||
|
const HISTORY = [
|
||||||
|
{ timestamp: 1, entry: 'testABC' },
|
||||||
|
{ timestamp: 2, entry: 'testDEF' }
|
||||||
|
];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
render(HISTORY);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders SectionList', () => {
|
||||||
|
expect(component.find('SectionList').length).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
27
js/src/views/Home/Dapps/dapps.test.js
Normal file
27
js/src/views/Home/Dapps/dapps.test.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
function createStore () {
|
||||||
|
return {
|
||||||
|
loadApp: sinon.stub().resolves({ name: 'testName' })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
createStore
|
||||||
|
};
|
17
js/src/views/Home/Dapps/index.js
Normal file
17
js/src/views/Home/Dapps/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// 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 './dapps';
|
17
js/src/views/Home/News/index.js
Normal file
17
js/src/views/Home/News/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// 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 './news';
|
73
js/src/views/Home/News/news.css
Normal file
73
js/src/views/Home/News/news.css
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.news {
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown {
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
height: 240px;
|
||||||
|
opacity: 0.85;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.background {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: cover;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
background: white;
|
||||||
|
color: #333;
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 100%;
|
||||||
|
padding: 0 1.5em 1em 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
background: rgba(255, 255, 255, 0.85);
|
||||||
|
bottom: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.17em;
|
||||||
|
left: 0;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
js/src/views/Home/News/news.js
Normal file
92
js/src/views/Home/News/news.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
|
import { SectionList } from '~/ui';
|
||||||
|
|
||||||
|
import { createRenderers } from './renderers';
|
||||||
|
import Store from './store';
|
||||||
|
import styles from './news.css';
|
||||||
|
|
||||||
|
const VERSION_ID = '1';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class News extends Component {
|
||||||
|
store = Store.get();
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
return this.store.retrieveNews(VERSION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { newsItems } = this.store;
|
||||||
|
|
||||||
|
if (!newsItems || !newsItems.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionList
|
||||||
|
className={ styles.news }
|
||||||
|
items={ newsItems }
|
||||||
|
renderItem={ this.renderItem }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderItem = (item) => {
|
||||||
|
if (!item) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inlineStyles = item.style || {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.item }>
|
||||||
|
<div
|
||||||
|
className={ styles.background }
|
||||||
|
style={ {
|
||||||
|
backgroundImage: `url(${item.background})`
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={ styles.title }
|
||||||
|
style={ inlineStyles.head }
|
||||||
|
>
|
||||||
|
{ item.title }
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={ styles.overlay }
|
||||||
|
style={ inlineStyles.body }
|
||||||
|
>
|
||||||
|
<ReactMarkdown
|
||||||
|
className={ styles.markdown }
|
||||||
|
renderers={ createRenderers(inlineStyles.tags) }
|
||||||
|
source={ item.markdown }
|
||||||
|
softBreak='br'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
VERSION_ID
|
||||||
|
};
|
54
js/src/views/Home/News/news.spec.js
Normal file
54
js/src/views/Home/News/news.spec.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import News from './news';
|
||||||
|
import { restoreGlobals, stubGlobals } from './news.test.js';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
component = shallow(
|
||||||
|
<News />
|
||||||
|
);
|
||||||
|
instance = component.instance();
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home/News', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
stubGlobals();
|
||||||
|
render();
|
||||||
|
|
||||||
|
return instance.componentWillMount();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
restoreGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(component).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('retrieves the content meta on mount', () => {
|
||||||
|
expect(instance.store.newsItems).to.equal('testContent');
|
||||||
|
});
|
||||||
|
});
|
54
js/src/views/Home/News/news.test.js
Normal file
54
js/src/views/Home/News/news.test.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import Contracts from '~/contracts';
|
||||||
|
|
||||||
|
import { VERSION_ID } from './news';
|
||||||
|
|
||||||
|
let contracts;
|
||||||
|
let globalContractsGet;
|
||||||
|
let globalFetch;
|
||||||
|
|
||||||
|
export function stubGlobals () {
|
||||||
|
contracts = {
|
||||||
|
githubHint: {
|
||||||
|
getEntry: sinon.stub().resolves(['testUrl', 'testOwner', 'testCommit'])
|
||||||
|
},
|
||||||
|
registry: {
|
||||||
|
lookupMeta: sinon.stub().resolves('testMeta')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
globalContractsGet = Contracts.get;
|
||||||
|
globalFetch = global.fetch;
|
||||||
|
|
||||||
|
sinon.stub(Contracts, 'get', () => contracts);
|
||||||
|
sinon.stub(global, 'fetch').resolves({
|
||||||
|
ok: true,
|
||||||
|
json: sinon.stub().resolves({
|
||||||
|
[VERSION_ID]: {
|
||||||
|
items: 'testContent'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function restoreGlobals () {
|
||||||
|
Contracts.get = globalContractsGet;
|
||||||
|
global.fetch = globalFetch;
|
||||||
|
}
|
37
js/src/views/Home/News/renderers.js
Normal file
37
js/src/views/Home/News/renderers.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { createElement } from 'react';
|
||||||
|
|
||||||
|
export function createRenderers (tagStyles = {}) {
|
||||||
|
return Object
|
||||||
|
.keys(tagStyles)
|
||||||
|
.reduce((renderers, tag) => {
|
||||||
|
switch (tag) {
|
||||||
|
case 'a':
|
||||||
|
case 'link':
|
||||||
|
renderers['link'] = (mdProps) => {
|
||||||
|
const { children, href, title } = mdProps;
|
||||||
|
const style = tagStyles[tag];
|
||||||
|
|
||||||
|
return createElement('a', { href, title, style }, children);
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderers;
|
||||||
|
}, {});
|
||||||
|
}
|
67
js/src/views/Home/News/store.js
Normal file
67
js/src/views/Home/News/store.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable } from 'mobx';
|
||||||
|
import Contracts from '~/contracts';
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
export default class Store {
|
||||||
|
@observable newsItems = null;
|
||||||
|
|
||||||
|
@action setNewsItems = (newsItems) => {
|
||||||
|
this.newsItems = newsItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
retrieveNews (versionId) {
|
||||||
|
const contracts = Contracts.get();
|
||||||
|
|
||||||
|
return contracts.registry
|
||||||
|
.lookupMeta('paritynews', 'CONTENT')
|
||||||
|
.then((contentId) => {
|
||||||
|
return contracts.githubHint.getEntry(contentId);
|
||||||
|
})
|
||||||
|
.then(([url, owner, commit]) => {
|
||||||
|
if (!url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(url).then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then((news) => {
|
||||||
|
if (news && news[versionId]) {
|
||||||
|
this.setNewsItems(news[versionId].items);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn('retrieveNews', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new Store();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
57
js/src/views/Home/News/store.spec.js
Normal file
57
js/src/views/Home/News/store.spec.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { VERSION_ID } from './news';
|
||||||
|
import { restoreGlobals, stubGlobals } from './news.test.js';
|
||||||
|
import Store from './store';
|
||||||
|
|
||||||
|
let store;
|
||||||
|
|
||||||
|
function create () {
|
||||||
|
store = new Store();
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home/News/Store', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
stubGlobals();
|
||||||
|
create();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
restoreGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('@action', () => {
|
||||||
|
describe('setNewsItems', () => {
|
||||||
|
it('sets the items', () => {
|
||||||
|
store.setNewsItems('testing');
|
||||||
|
expect(store.newsItems).to.equal('testing');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('operations', () => {
|
||||||
|
describe('retrieveNews', () => {
|
||||||
|
it('retrieves the items', () => {
|
||||||
|
return store.retrieveNews(VERSION_ID).then(() => {
|
||||||
|
expect(store.newsItems).to.equal('testContent');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
17
js/src/views/Home/Urls/index.js
Normal file
17
js/src/views/Home/Urls/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// 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 './urls';
|
80
js/src/views/Home/Urls/urls.css
Normal file
80
js/src/views/Home/Urls/urls.css
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.urls {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 1.5em auto;
|
||||||
|
padding: 0 1em;
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.historyItem {
|
||||||
|
height: auto;
|
||||||
|
margin-top: 1em;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.linkIcon {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5em;
|
||||||
|
top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.url {
|
||||||
|
display: block;
|
||||||
|
color: rgb(0, 151, 167);
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timestamp {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
.linkIcon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
border-radius: 0.25em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: white;
|
||||||
|
display: block;
|
||||||
|
font-size: 1.25em;
|
||||||
|
padding: 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
139
js/src/views/Home/Urls/urls.js
Normal file
139
js/src/views/Home/Urls/urls.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Container, ContainerTitle, DappUrlInput, SectionList } from '~/ui';
|
||||||
|
import { LinkIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
|
import styles from './urls.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Urls extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
router: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
extensionStore: PropTypes.object.isRequired,
|
||||||
|
store: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { nextUrl } = this.props.store;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.urls }>
|
||||||
|
<div className={ styles.layout }>
|
||||||
|
<ContainerTitle
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.url.title'
|
||||||
|
defaultMessage='Web Applications'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<DappUrlInput
|
||||||
|
className={ styles.input }
|
||||||
|
onChange={ this.onChangeUrl }
|
||||||
|
onGoto={ this.onGotoUrl }
|
||||||
|
onRestore={ this.onRestoreUrl }
|
||||||
|
url={ nextUrl }
|
||||||
|
/>
|
||||||
|
{ this.renderHistory() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHistory () {
|
||||||
|
const { history } = this.props.store;
|
||||||
|
|
||||||
|
if (!history.length) {
|
||||||
|
return (
|
||||||
|
<div className={ styles.empty }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.url.none'
|
||||||
|
defaultMessage='No recent URL history available'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionList
|
||||||
|
items={ history }
|
||||||
|
renderItem={ this.renderHistoryItem }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHistoryItem = (history) => {
|
||||||
|
if (!history || !history.url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onNavigate = () => this.onGotoUrl(history.url);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
className={ styles.historyItem }
|
||||||
|
hover={
|
||||||
|
<div className={ styles.timestamp }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.url.visited'
|
||||||
|
defaultMessage='visited {when}'
|
||||||
|
values={ {
|
||||||
|
when: moment(history.timestamp).fromNow()
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
key={ history.timestamp }
|
||||||
|
onClick={ onNavigate }
|
||||||
|
>
|
||||||
|
<LinkIcon className={ styles.linkIcon } />
|
||||||
|
<div className={ styles.url }>
|
||||||
|
{ history.hostname }
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeUrl = (url) => {
|
||||||
|
this.props.store.setNextUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
onGotoUrl = (url) => {
|
||||||
|
const { router } = this.context;
|
||||||
|
const { extensionStore } = this.props;
|
||||||
|
|
||||||
|
this.props.store.gotoUrl(url);
|
||||||
|
|
||||||
|
if (extensionStore.hasExtension) {
|
||||||
|
window.open(this.props.store.currentUrl, '_blank');
|
||||||
|
} else {
|
||||||
|
router.push('/web');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRestoreUrl = () => {
|
||||||
|
this.props.store.restoreUrl();
|
||||||
|
}
|
||||||
|
}
|
124
js/src/views/Home/Urls/urls.spec.js
Normal file
124
js/src/views/Home/Urls/urls.spec.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import Urls from './';
|
||||||
|
|
||||||
|
const NEXT_URL = 'http://somewhere.next';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let instance;
|
||||||
|
let router;
|
||||||
|
let store;
|
||||||
|
|
||||||
|
function createRouter () {
|
||||||
|
router = {
|
||||||
|
push: sinon.stub()
|
||||||
|
};
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createStore () {
|
||||||
|
store = {
|
||||||
|
history: [],
|
||||||
|
gotoUrl: sinon.stub(),
|
||||||
|
restoreUrl: sinon.stub(),
|
||||||
|
setNextUrl: sinon.stub(),
|
||||||
|
nextUrl: NEXT_URL
|
||||||
|
};
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
component = shallow(
|
||||||
|
<Urls
|
||||||
|
extensionStore={ { hasExtension: false } }
|
||||||
|
store={ createStore() }
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
router: createRouter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
instance = component.instance();
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home/Urls', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(component).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('input', () => {
|
||||||
|
let input;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
input = component.find('DappUrlInput');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the input cmponent', () => {
|
||||||
|
expect(input.length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes nextUrl as url', () => {
|
||||||
|
expect(input.props().url).to.equal(NEXT_URL);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('events', () => {
|
||||||
|
describe('onChangeUrl', () => {
|
||||||
|
it('performs setNextUrl on store', () => {
|
||||||
|
instance.onChangeUrl('123');
|
||||||
|
expect(store.setNextUrl).to.have.been.calledWith('123');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onGotoUrl', () => {
|
||||||
|
it('performs gotoUrl on store', () => {
|
||||||
|
instance.onGotoUrl();
|
||||||
|
expect(store.gotoUrl).to.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passed the URL when provided', () => {
|
||||||
|
instance.onGotoUrl('http://example.com');
|
||||||
|
expect(store.gotoUrl).to.have.been.calledWith('http://example.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does route navigation when executed', () => {
|
||||||
|
instance.onGotoUrl();
|
||||||
|
expect(router.push).to.have.been.calledWith('/web');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onRestoreUrl', () => {
|
||||||
|
it('performs restoreUrl on store', () => {
|
||||||
|
instance.onRestoreUrl();
|
||||||
|
expect(store.restoreUrl).to.have.been.called;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -15,6 +15,26 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.button {
|
.accounts {
|
||||||
vertical-align: middle;
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
padding-bottom: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.column {
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 0 1 50%;
|
||||||
|
padding: 0 1.5em;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
81
js/src/views/Home/home.js
Normal file
81
js/src/views/Home/home.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Page } from '~/ui';
|
||||||
|
|
||||||
|
import DappsStore from '../Dapps/dappsStore';
|
||||||
|
import ExtensionStore from '../Application/Extension/store';
|
||||||
|
import HistoryStore from '../historyStore';
|
||||||
|
import WebStore from '../Web/store';
|
||||||
|
|
||||||
|
import Accounts from './Accounts';
|
||||||
|
import Dapps from './Dapps';
|
||||||
|
import News from './News';
|
||||||
|
import Urls from './Urls';
|
||||||
|
import styles from './home.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Home extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
api: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
dappsStore = DappsStore.get(this.context.api);
|
||||||
|
extensionStore = ExtensionStore.get();
|
||||||
|
webStore = WebStore.get(this.context.api);
|
||||||
|
|
||||||
|
accountsHistory = HistoryStore.get('accounts');
|
||||||
|
dappsHistory = HistoryStore.get('dapps');
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
return this.webStore.loadHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<Page
|
||||||
|
className={ styles.body }
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.title'
|
||||||
|
defaultMessage='Parity Home'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<News />
|
||||||
|
<Urls
|
||||||
|
extensionStore={ this.extensionStore }
|
||||||
|
store={ this.webStore }
|
||||||
|
/>
|
||||||
|
<div className={ styles.row }>
|
||||||
|
<div className={ styles.column }>
|
||||||
|
<Dapps
|
||||||
|
history={ this.dappsHistory.history }
|
||||||
|
store={ this.dappsStore }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.column }>
|
||||||
|
<Accounts history={ this.accountsHistory.history } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
96
js/src/views/Home/home.spec.js
Normal file
96
js/src/views/Home/home.spec.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import Home from './';
|
||||||
|
|
||||||
|
const TEST_APP_HISTORY = [];
|
||||||
|
|
||||||
|
let api;
|
||||||
|
let component;
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
function createApi () {
|
||||||
|
api = {
|
||||||
|
parity: {
|
||||||
|
listRecentDapps: sinon.stub().resolves(TEST_APP_HISTORY)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
component = shallow(
|
||||||
|
<Home />,
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
api: createApi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
instance = component.instance();
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('views/Home', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(component).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('lifecycle', () => {
|
||||||
|
describe('componentWillMount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
sinon.stub(instance.webStore, 'loadHistory');
|
||||||
|
return instance.componentWillMount();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
instance.webStore.loadHistory.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls into webStore loadHistory', () => {
|
||||||
|
expect(instance.webStore.loadHistory).to.have.been.called;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('components', () => {
|
||||||
|
it('renders Accounts', () => {
|
||||||
|
expect(component.find('Connect(Accounts)').length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders Dapps', () => {
|
||||||
|
expect(component.find('Dapps').length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders News', () => {
|
||||||
|
expect(component.find('News').length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders Urls', () => {
|
||||||
|
expect(component.find('Urls').length).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
17
js/src/views/Home/index.js
Normal file
17
js/src/views/Home/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// 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 './home';
|
@ -19,20 +19,7 @@ $overlayZ: 10000;
|
|||||||
$modalZ: 10001;
|
$modalZ: 10001;
|
||||||
|
|
||||||
.account {
|
.account {
|
||||||
display: flex;
|
width: 100%;
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.accountOverlay {
|
|
||||||
position: absolute;
|
|
||||||
right: 0.5em;
|
|
||||||
top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconDisabled {
|
|
||||||
opacity: 0.15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected,
|
.selected,
|
||||||
.unselected {
|
.unselected {
|
||||||
|
@ -23,7 +23,24 @@ import CommunicationContacts from 'material-ui/svg-icons/communication/contacts'
|
|||||||
import ImageGridOn from 'material-ui/svg-icons/image/grid-on';
|
import ImageGridOn from 'material-ui/svg-icons/image/grid-on';
|
||||||
import NavigationApps from 'material-ui/svg-icons/navigation/apps';
|
import NavigationApps from 'material-ui/svg-icons/navigation/apps';
|
||||||
|
|
||||||
|
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
|
||||||
|
|
||||||
|
import styles from './views.css';
|
||||||
|
|
||||||
const defaultViews = {
|
const defaultViews = {
|
||||||
|
home: {
|
||||||
|
active: true,
|
||||||
|
fixed: true,
|
||||||
|
icon: (
|
||||||
|
<img
|
||||||
|
className={ styles.logoIcon }
|
||||||
|
src={ imagesEthcoreBlock }
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
route: '/home',
|
||||||
|
value: 'home'
|
||||||
|
},
|
||||||
|
|
||||||
accounts: {
|
accounts: {
|
||||||
active: true,
|
active: true,
|
||||||
fixed: true,
|
fixed: true,
|
||||||
|
@ -43,6 +43,12 @@
|
|||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logoIcon {
|
||||||
|
height: 24px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
padding-left: 4.75em;
|
padding-left: 4.75em;
|
||||||
|
@ -82,8 +82,31 @@ export default class Store {
|
|||||||
this.setNextUrl(this.currentUrl);
|
this.setNextUrl(this.currentUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action setHistory = (history) => {
|
@action setHistory = (urls) => {
|
||||||
this.history = history;
|
this.history = Object
|
||||||
|
.keys(urls)
|
||||||
|
.filter((url) => url && !url.startsWith(this._api.dappsUrl) && url.indexOf('127.0.0.1') === -1)
|
||||||
|
.sort((urlA, urlB) => {
|
||||||
|
const timeA = urls[urlA].getTime();
|
||||||
|
const timeB = urls[urlB].getTime();
|
||||||
|
|
||||||
|
if (timeA > timeB) {
|
||||||
|
return -1;
|
||||||
|
} else if (timeA < timeB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
.map((url) => {
|
||||||
|
const hostname = url.replace(/^http[s]?:\/\//, '').split('/')[0];
|
||||||
|
|
||||||
|
return {
|
||||||
|
hostname,
|
||||||
|
timestamp: urls[url],
|
||||||
|
url
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@action setLoading = (isLoading) => {
|
@action setLoading = (isLoading) => {
|
||||||
|
@ -18,7 +18,13 @@ import sinon from 'sinon';
|
|||||||
|
|
||||||
import Store from './store';
|
import Store from './store';
|
||||||
|
|
||||||
const TEST_HISTORY = ['somethingA', 'somethingB'];
|
const TEST_HISTORY_URLA = 'http://testingA';
|
||||||
|
const TEST_HISTORY_URLB = 'http://testingB';
|
||||||
|
const TEST_HISTORY = {
|
||||||
|
'': new Date(678),
|
||||||
|
[TEST_HISTORY_URLA]: new Date(123),
|
||||||
|
[TEST_HISTORY_URLB]: new Date(456)
|
||||||
|
};
|
||||||
const TEST_TOKEN = 'testing-123';
|
const TEST_TOKEN = 'testing-123';
|
||||||
const TEST_URL1 = 'http://some.test.domain.com';
|
const TEST_URL1 = 'http://some.test.domain.com';
|
||||||
const TEST_URL2 = 'http://something.different.com';
|
const TEST_URL2 = 'http://something.different.com';
|
||||||
@ -89,9 +95,28 @@ describe('views/Web/Store', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('setHistory', () => {
|
describe('setHistory', () => {
|
||||||
it('sets the history', () => {
|
let history;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
store.setHistory(TEST_HISTORY);
|
store.setHistory(TEST_HISTORY);
|
||||||
expect(store.history.peek()).to.deep.equal(TEST_HISTORY);
|
history = store.history.peek();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the history', () => {
|
||||||
|
expect(history.length).to.equal(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds hostname to entries', () => {
|
||||||
|
expect(history[1].hostname).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes hostname http prefixes', () => {
|
||||||
|
expect(history[1].hostname.indexOf('http')).to.equal(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sorts the entries according to recently accessed', () => {
|
||||||
|
expect(history[0].url).to.equal(TEST_HISTORY_URLB);
|
||||||
|
expect(history[1].url).to.equal(TEST_HISTORY_URLA);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -195,7 +220,7 @@ describe('views/Web/Store', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('sets the history as retrieved', () => {
|
it('sets the history as retrieved', () => {
|
||||||
expect(store.history.peek()).to.deep.equal(TEST_HISTORY);
|
expect(store.history.peek().length).not.to.equal(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -30,10 +30,11 @@ export default class Store {
|
|||||||
this.load();
|
this.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action add = (entry) => {
|
@action add = (entry, type) => {
|
||||||
this.history = [{
|
this.history = [{
|
||||||
|
entry,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
entry
|
type
|
||||||
}].concat(this.history.filter((h) => h.entry !== entry)).slice(0, MAX_ENTRIES);
|
}].concat(this.history.filter((h) => h.entry !== entry)).slice(0, MAX_ENTRIES);
|
||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ export Contracts from './Contracts';
|
|||||||
export Dapp from './Dapp';
|
export Dapp from './Dapp';
|
||||||
export Dapps from './Dapps';
|
export Dapps from './Dapps';
|
||||||
export HistoryStore from './historyStore';
|
export HistoryStore from './historyStore';
|
||||||
|
export Home from './Home';
|
||||||
export ParityBar from './ParityBar';
|
export ParityBar from './ParityBar';
|
||||||
export Settings, { SettingsBackground, SettingsParity, SettingsProxy, SettingsViews } from './Settings';
|
export Settings, { SettingsBackground, SettingsParity, SettingsProxy, SettingsViews } from './Settings';
|
||||||
export Signer from './Signer';
|
export Signer from './Signer';
|
||||||
|
Loading…
Reference in New Issue
Block a user