aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts')
-rw-r--r--packages/website/ts/components/eth_wrappers.tsx59
-rw-r--r--packages/website/ts/components/portal.tsx40
-rw-r--r--packages/website/ts/components/portal_menu.tsx13
-rw-r--r--packages/website/ts/components/sidebar_header.tsx10
-rw-r--r--packages/website/ts/components/token_balances.tsx9
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx122
-rw-r--r--packages/website/ts/components/wallet.tsx373
-rw-r--r--packages/website/ts/containers/deployer_documentation.ts102
-rw-r--r--packages/website/ts/containers/json_schemas_documentation.ts89
-rw-r--r--packages/website/ts/containers/sol_cov_documentation.ts89
-rw-r--r--packages/website/ts/containers/subproviders_documentation.ts141
-rw-r--r--packages/website/ts/containers/web3_wrapper_documentation.ts103
-rw-r--r--packages/website/ts/containers/zero_ex_js_documentation.ts12
-rw-r--r--packages/website/ts/index.tsx29
-rw-r--r--packages/website/ts/pages/documentation/doc_page.tsx36
-rw-r--r--packages/website/ts/pages/faq/faq.tsx4
-rw-r--r--packages/website/ts/pages/landing/landing.tsx12
-rw-r--r--packages/website/ts/pages/wiki/wiki.tsx4
-rw-r--r--packages/website/ts/types.ts98
-rw-r--r--packages/website/ts/utils/constants.ts5
-rw-r--r--packages/website/ts/utils/doc_utils.ts60
21 files changed, 1270 insertions, 140 deletions
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx
index b12c637e5..59afeb50b 100644
--- a/packages/website/ts/components/eth_wrappers.tsx
+++ b/packages/website/ts/components/eth_wrappers.tsx
@@ -10,7 +10,14 @@ import ReactTooltip = require('react-tooltip');
import { Blockchain } from 'ts/blockchain';
import { EthWethConversionButton } from 'ts/components/eth_weth_conversion_button';
import { Dispatcher } from 'ts/redux/dispatcher';
-import { OutdatedWrappedEtherByNetworkId, Side, Token, TokenByAddress, TokenState } from 'ts/types';
+import {
+ OutdatedWrappedEtherByNetworkId,
+ Side,
+ Token,
+ TokenByAddress,
+ TokenState,
+ TokenStateByAddress,
+} from 'ts/types';
import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';
@@ -20,13 +27,6 @@ const ICON_DIMENSION = 40;
const ETHER_ICON_PATH = '/images/ether.png';
const OUTDATED_WETH_ICON_PATH = '/images/wrapped_eth_gray.png';
-interface OutdatedWETHAddressToIsStateLoaded {
- [address: string]: boolean;
-}
-interface OutdatedWETHStateByAddress {
- [address: string]: TokenState;
-}
-
interface EthWrappersProps {
networkId: number;
blockchain: Blockchain;
@@ -39,9 +39,7 @@ interface EthWrappersProps {
interface EthWrappersState {
ethTokenState: TokenState;
- isWethStateLoaded: boolean;
- outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded;
- outdatedWETHStateByAddress: OutdatedWETHStateByAddress;
+ outdatedWETHStateByAddress: TokenStateByAddress;
}
export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
@@ -50,22 +48,20 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
super(props);
this._isUnmounted = false;
const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
- const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
- const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
+ const outdatedWETHStateByAddress: TokenStateByAddress = {};
_.each(outdatedWETHAddresses, outdatedWETHAddress => {
- outdatedWETHAddressToIsStateLoaded[outdatedWETHAddress] = false;
outdatedWETHStateByAddress[outdatedWETHAddress] = {
balance: new BigNumber(0),
allowance: new BigNumber(0),
+ isLoaded: false,
};
});
this.state = {
- outdatedWETHAddressToIsStateLoaded,
outdatedWETHStateByAddress,
- isWethStateLoaded: false,
ethTokenState: {
balance: new BigNumber(0),
allowance: new BigNumber(0),
+ isLoaded: false,
},
};
}
@@ -169,7 +165,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
{this._renderTokenLink(tokenLabel, etherscanUrl)}
</TableRowColumn>
<TableRowColumn>
- {this.state.isWethStateLoaded ? (
+ {this.state.ethTokenState.isLoaded ? (
`${wethBalance.toFixed(configs.AMOUNT_DISPLAY_PRECSION)} WETH`
) : (
<i className="zmdi zmdi-spinner zmdi-hc-spin" />
@@ -183,7 +179,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
networkId={this.props.networkId}
isOutdatedWrappedEther={false}
direction={Side.Receive}
- isDisabled={!this.state.isWethStateLoaded}
+ isDisabled={!this.state.ethTokenState.isLoaded}
ethToken={etherToken}
dispatcher={this.props.dispatcher}
blockchain={this.props.blockchain}
@@ -266,8 +262,8 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
...etherToken,
address: outdatedWETHIfExists.address,
};
- const isStateLoaded = this.state.outdatedWETHAddressToIsStateLoaded[outdatedWETHIfExists.address];
const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETHIfExists.address];
+ const isStateLoaded = outdatedEtherTokenState.isLoaded;
const balanceInEthIfExists = isStateLoaded
? ZeroEx.toUnitAmount(outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH).toFixed(
configs.AMOUNT_DISPLAY_PRECSION,
@@ -345,10 +341,15 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
);
}
private async _onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) {
+ const currentOutdatedWETHState = this.state.outdatedWETHStateByAddress[outdatedWETHAddress];
this.setState({
- outdatedWETHAddressToIsStateLoaded: {
- ...this.state.outdatedWETHAddressToIsStateLoaded,
- [outdatedWETHAddress]: false,
+ outdatedWETHStateByAddress: {
+ ...this.state.outdatedWETHStateByAddress,
+ [outdatedWETHAddress]: {
+ balance: currentOutdatedWETHState.balance,
+ allowance: currentOutdatedWETHState.allowance,
+ isLoaded: false,
+ },
},
});
const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
@@ -357,15 +358,12 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
outdatedWETHAddress,
);
this.setState({
- outdatedWETHAddressToIsStateLoaded: {
- ...this.state.outdatedWETHAddressToIsStateLoaded,
- [outdatedWETHAddress]: true,
- },
outdatedWETHStateByAddress: {
...this.state.outdatedWETHStateByAddress,
[outdatedWETHAddress]: {
balance,
allowance,
+ isLoaded: true,
},
},
});
@@ -380,8 +378,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
);
const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
- const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
- const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
+ const outdatedWETHStateByAddress: TokenStateByAddress = {};
for (const address of outdatedWETHAddresses) {
const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
userAddressIfExists,
@@ -390,18 +387,17 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
outdatedWETHStateByAddress[address] = {
balance,
allowance,
+ isLoaded: true,
};
- outdatedWETHAddressToIsStateLoaded[address] = true;
}
if (!this._isUnmounted) {
this.setState({
outdatedWETHStateByAddress,
- outdatedWETHAddressToIsStateLoaded,
ethTokenState: {
balance: wethBalance,
allowance: wethAllowance,
+ isLoaded: true,
},
- isWethStateLoaded: true,
});
}
}
@@ -434,6 +430,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
ethTokenState: {
balance,
allowance,
+ isLoaded: true,
},
});
}
diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/portal.tsx
index 5bdb5bde9..59eaca67e 100644
--- a/packages/website/ts/components/portal.tsx
+++ b/packages/website/ts/components/portal.tsx
@@ -19,12 +19,22 @@ import { TokenBalances } from 'ts/components/token_balances';
import { TopBar } from 'ts/components/top_bar/top_bar';
import { TradeHistory } from 'ts/components/trade_history/trade_history';
import { FlashMessage } from 'ts/components/ui/flash_message';
+import { Wallet } from 'ts/components/wallet';
import { GenerateOrderForm } from 'ts/containers/generate_order_form';
import { localStorage } from 'ts/local_storage/local_storage';
import { Dispatcher } from 'ts/redux/dispatcher';
import { portalOrderSchema } from 'ts/schemas/portal_order_schema';
import { validator } from 'ts/schemas/validator';
-import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, WebsitePaths } from 'ts/types';
+import {
+ BlockchainErrs,
+ Environments,
+ HashData,
+ Order,
+ ProviderType,
+ ScreenWidths,
+ TokenByAddress,
+ WebsitePaths,
+} from 'ts/types';
import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
@@ -194,6 +204,12 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
<div className="py2" style={{ backgroundColor: colors.grey50 }}>
{this.props.blockchainIsLoaded ? (
<Switch>
+ {configs.ENVIRONMENT === Environments.DEVELOPMENT && (
+ <Route
+ path={`${WebsitePaths.Portal}/wallet`}
+ render={this._renderWallet.bind(this)}
+ />
+ )}
<Route
path={`${WebsitePaths.Portal}/weth`}
render={this._renderEthWrapper.bind(this)}
@@ -272,6 +288,28 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
});
}
+ private _renderWallet() {
+ const allTokens = _.values(this.props.tokenByAddress);
+ const trackedTokens = _.filter(allTokens, t => t.isTracked);
+ return (
+ <div className="flex flex-center">
+ <div className="mx-auto">
+ <Wallet
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ blockchainIsLoaded={this.props.blockchainIsLoaded}
+ blockchainErr={this.props.blockchainErr}
+ dispatcher={this.props.dispatcher}
+ tokenByAddress={this.props.tokenByAddress}
+ trackedTokens={trackedTokens}
+ userEtherBalanceInWei={this.props.userEtherBalanceInWei}
+ lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
+ />
+ </div>
+ </div>
+ );
+ }
private _renderEthWrapper() {
return (
<EthWrappers
diff --git a/packages/website/ts/components/portal_menu.tsx b/packages/website/ts/components/portal_menu.tsx
index a2f9340c8..9ab611556 100644
--- a/packages/website/ts/components/portal_menu.tsx
+++ b/packages/website/ts/components/portal_menu.tsx
@@ -1,7 +1,8 @@
import * as _ from 'lodash';
import * as React from 'react';
import { MenuItem } from 'ts/components/ui/menu_item';
-import { WebsitePaths } from 'ts/types';
+import { Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
export interface PortalMenuProps {
menuItemStyle: React.CSSProperties;
@@ -57,6 +58,16 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState
>
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
</MenuItem>
+ {configs.ENVIRONMENT === Environments.DEVELOPMENT && (
+ <MenuItem
+ style={this.props.menuItemStyle}
+ className="py2"
+ to={`${WebsitePaths.Portal}/wallet`}
+ onClick={this.props.onClick.bind(this)}
+ >
+ {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')}
+ </MenuItem>
+ )}
</div>
);
}
diff --git a/packages/website/ts/components/sidebar_header.tsx b/packages/website/ts/components/sidebar_header.tsx
index 519b23d80..a0ea869fb 100644
--- a/packages/website/ts/components/sidebar_header.tsx
+++ b/packages/website/ts/components/sidebar_header.tsx
@@ -4,15 +4,9 @@ import * as React from 'react';
const SHOW_DURATION_MS = 4000;
-const titleToIcon: { [title: string]: string } = {
- '0x.js': 'zeroExJs.png',
- '0x Connect': 'connect.png',
- '0x Smart Contracts': 'contracts.png',
- Wiki: 'wiki.png',
-};
-
interface SidebarHeaderProps {
title: string;
+ iconUrl: string;
}
interface SidebarHeaderState {}
@@ -32,7 +26,7 @@ export class SidebarHeader extends React.Component<SidebarHeaderProps, SidebarHe
</div>
<div className="flex">
<div>
- <img src={`/images/doc_icons/${titleToIcon[this.props.title]}`} width="22" />
+ <img src={this.props.iconUrl} width="22" />
</div>
<div className="pl1" style={{ fontWeight: 600, fontSize: 20, lineHeight: 1.2 }}>
{this.props.title}
diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx
index 186393c4f..b4a710ef4 100644
--- a/packages/website/ts/components/token_balances.tsx
+++ b/packages/website/ts/components/token_balances.tsx
@@ -37,6 +37,7 @@ import {
ScreenWidths,
Token,
TokenByAddress,
+ TokenStateByAddress,
TokenVisibility,
} from 'ts/types';
import { configs } from 'ts/utils/configs';
@@ -61,14 +62,6 @@ const styles: Styles = {
},
};
-interface TokenStateByAddress {
- [address: string]: {
- balance: BigNumber;
- allowance: BigNumber;
- isLoaded: boolean;
- };
-}
-
interface TokenBalancesProps {
blockchain: Blockchain;
blockchainErr: BlockchainErrs;
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index 29c68524c..4b2e82119 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -39,6 +39,7 @@ interface TopBarProps {
style?: React.CSSProperties;
isNightVersion?: boolean;
onVersionSelected?: (semver: string) => void;
+ sidebarHeader?: React.ReactNode;
}
interface TopBarState {
@@ -120,14 +121,36 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
primaryText={this.props.translate.get(Key.StandardRelayerApi, Deco.CapWords)}
/>
</a>,
- <a
- key="subMenuItem-github"
- target="_blank"
- className="text-decoration-none"
- href={constants.URL_GITHUB_ORG}
- >
- <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="GitHub" />
- </a>,
+ <Link key="subMenuItem-jsonSchema" to={WebsitePaths.JSONSchemas} className="text-decoration-none">
+ <MenuItem
+ style={{ fontSize: styles.menuItem.fontSize }}
+ primaryText={this.props.translate.get(Key.JsonSchemas, Deco.CapWords)}
+ />
+ </Link>,
+ <Link key="subMenuItem-subproviders" to={WebsitePaths.Subproviders} className="text-decoration-none">
+ <MenuItem
+ style={{ fontSize: styles.menuItem.fontSize }}
+ primaryText={this.props.translate.get(Key.Subproviders, Deco.CapWords)}
+ />
+ </Link>,
+ <Link key="subMenuItem-web3Wrapper" to={WebsitePaths.Web3Wrapper} className="text-decoration-none">
+ <MenuItem
+ style={{ fontSize: styles.menuItem.fontSize }}
+ primaryText={this.props.translate.get(Key.Web3Wrapper, Deco.CapWords)}
+ />
+ </Link>,
+ <Link key="subMenuItem-deployer" to={WebsitePaths.Deployer} className="text-decoration-none">
+ <MenuItem
+ style={{ fontSize: styles.menuItem.fontSize }}
+ primaryText={this.props.translate.get(Key.Deployer, Deco.CapWords)}
+ />
+ </Link>,
+ <Link key="subMenuItem-sol-cov" to={WebsitePaths.SolCov} className="text-decoration-none">
+ <MenuItem
+ style={{ fontSize: styles.menuItem.fontSize }}
+ primaryText={this.props.translate.get(Key.SolCov, Deco.CapWords)}
+ />
+ </Link>,
<a
key="subMenuItem-whitePaper"
target="_blank"
@@ -139,6 +162,14 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
primaryText={this.props.translate.get(Key.Whitepaper, Deco.CapWords)}
/>
</a>,
+ <a
+ key="subMenuItem-github"
+ target="_blank"
+ className="text-decoration-none"
+ href={constants.URL_GITHUB_ORG}
+ >
+ <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="GitHub" />
+ </a>,
];
const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
@@ -277,6 +308,46 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</MenuItem>
</Link>
)}
+ {!this._isViewingWeb3WrapperDocs() && (
+ <Link to={WebsitePaths.Web3Wrapper} className="text-decoration-none">
+ <MenuItem className="py2">
+ {this.props.translate.get(Key.Web3Wrapper, Deco.Cap)}{' '}
+ {this.props.translate.get(Key.Docs, Deco.Cap)}
+ </MenuItem>
+ </Link>
+ )}
+ {!this._isViewingDeployerDocs() && (
+ <Link to={WebsitePaths.Deployer} className="text-decoration-none">
+ <MenuItem className="py2">
+ {this.props.translate.get(Key.Deployer, Deco.Cap)}{' '}
+ {this.props.translate.get(Key.Docs, Deco.Cap)}
+ </MenuItem>
+ </Link>
+ )}
+ {!this._isViewingJsonSchemasDocs() && (
+ <Link to={WebsitePaths.JSONSchemas} className="text-decoration-none">
+ <MenuItem className="py2">
+ {this.props.translate.get(Key.JsonSchemas, Deco.Cap)}{' '}
+ {this.props.translate.get(Key.Docs, Deco.Cap)}
+ </MenuItem>
+ </Link>
+ )}
+ {!this._isViewingSolCovDocs() && (
+ <Link to={WebsitePaths.SolCov} className="text-decoration-none">
+ <MenuItem className="py2">
+ {this.props.translate.get(Key.SolCov, Deco.Cap)}{' '}
+ {this.props.translate.get(Key.Docs, Deco.Cap)}
+ </MenuItem>
+ </Link>
+ )}
+ {!this._isViewingSubprovidersDocs() && (
+ <Link to={WebsitePaths.Subproviders} className="text-decoration-none">
+ <MenuItem className="py2">
+ {this.props.translate.get(Key.Subproviders, Deco.Cap)}{' '}
+ {this.props.translate.get(Key.Docs, Deco.Cap)}
+ </MenuItem>
+ </Link>
+ )}
{!this._isViewingPortal() && (
<Link to={`${WebsitePaths.Portal}`} className="text-decoration-none">
<MenuItem className="py2">
@@ -304,7 +375,14 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
}
private _renderDocsMenu(): React.ReactNode {
if (
- (!this._isViewing0xjsDocs() && !this._isViewingSmartContractsDocs() && !this._isViewingConnectDocs()) ||
+ (!this._isViewing0xjsDocs() &&
+ !this._isViewingSmartContractsDocs() &&
+ !this._isViewingWeb3WrapperDocs() &&
+ !this._isViewingDeployerDocs() &&
+ !this._isViewingJsonSchemasDocs() &&
+ !this._isViewingSolCovDocs() &&
+ !this._isViewingSubprovidersDocs() &&
+ !this._isViewingConnectDocs()) ||
_.isUndefined(this.props.menu)
) {
return undefined;
@@ -316,7 +394,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
<NestedSidebarMenu
topLevelMenu={this.props.menu}
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
- sidebarHeader={<SidebarHeader title={this.props.docsInfo.displayName} />}
+ sidebarHeader={this.props.sidebarHeader}
shouldDisplaySectionHeaders={false}
onMenuItemClick={this._onMenuButtonClick.bind(this)}
selectedVersion={this.props.docsVersion}
@@ -336,7 +414,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
<NestedSidebarMenu
topLevelMenu={this.props.menuSubsectionsBySection}
menuSubsectionsBySection={this.props.menuSubsectionsBySection}
- sidebarHeader={<SidebarHeader title="Wiki" />}
+ sidebarHeader={this.props.sidebarHeader}
shouldDisplaySectionHeaders={false}
onMenuItemClick={this._onMenuButtonClick.bind(this)}
/>
@@ -392,6 +470,21 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
private _isViewingSmartContractsDocs() {
return _.includes(this.props.location.pathname, WebsitePaths.SmartContracts);
}
+ private _isViewingWeb3WrapperDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.Web3Wrapper);
+ }
+ private _isViewingDeployerDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.Deployer);
+ }
+ private _isViewingJsonSchemasDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.JSONSchemas);
+ }
+ private _isViewingSolCovDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.SolCov);
+ }
+ private _isViewingSubprovidersDocs() {
+ return _.includes(this.props.location.pathname, WebsitePaths.Subproviders);
+ }
private _isViewingWiki() {
return _.includes(this.props.location.pathname, WebsitePaths.Wiki);
}
@@ -401,7 +494,12 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
this._isViewing0xjsDocs() ||
this._isViewingFAQ() ||
this._isViewingSmartContractsDocs() ||
+ this._isViewingWeb3WrapperDocs() ||
+ this._isViewingDeployerDocs() ||
+ this._isViewingJsonSchemasDocs() ||
+ this._isViewingSolCovDocs() ||
+ this._isViewingSubprovidersDocs() ||
this._isViewingConnectDocs()
);
}
-}
+} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/wallet.tsx b/packages/website/ts/components/wallet.tsx
new file mode 100644
index 000000000..8c6ef9cad
--- /dev/null
+++ b/packages/website/ts/components/wallet.tsx
@@ -0,0 +1,373 @@
+import { ZeroEx } from '0x.js';
+import {
+ colors,
+ constants as sharedConstants,
+ EtherscanLinkSuffixes,
+ Styles,
+ utils as sharedUtils,
+} from '@0xproject/react-shared';
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+import FlatButton from 'material-ui/FlatButton';
+import { List, ListItem } from 'material-ui/List';
+import NavigationArrowDownward from 'material-ui/svg-icons/navigation/arrow-downward';
+import NavigationArrowUpward from 'material-ui/svg-icons/navigation/arrow-upward';
+import * as React from 'react';
+import ReactTooltip = require('react-tooltip');
+import firstBy = require('thenby');
+
+import { Blockchain } from 'ts/blockchain';
+import { AllowanceToggle } from 'ts/components/inputs/allowance_toggle';
+import { Identicon } from 'ts/components/ui/identicon';
+import { TokenIcon } from 'ts/components/ui/token_icon';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { BalanceErrs, BlockchainErrs, Token, TokenByAddress, TokenState, TokenStateByAddress } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { utils } from 'ts/utils/utils';
+
+export interface WalletProps {
+ userAddress?: string;
+ networkId?: number;
+ blockchain: Blockchain;
+ blockchainIsLoaded: boolean;
+ blockchainErr: BlockchainErrs;
+ dispatcher: Dispatcher;
+ tokenByAddress: TokenByAddress;
+ trackedTokens: Token[];
+ userEtherBalanceInWei: BigNumber;
+ lastForceTokenStateRefetch: number;
+}
+
+interface WalletState {
+ trackedTokenStateByAddress: TokenStateByAddress;
+}
+
+enum WrappedEtherAction {
+ Wrap,
+ Unwrap,
+}
+
+interface AllowanceToggleConfig {
+ token: Token;
+ tokenState: TokenState;
+}
+
+interface AccessoryItemConfig {
+ wrappedEtherAction?: WrappedEtherAction;
+ allowanceToggleConfig?: AllowanceToggleConfig;
+}
+
+const styles: Styles = {
+ wallet: {
+ width: 346,
+ backgroundColor: colors.white,
+ borderBottomRightRadius: 10,
+ borderBottomLeftRadius: 10,
+ borderTopRightRadius: 10,
+ borderTopLeftRadius: 10,
+ boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`,
+ overflow: 'hidden',
+ },
+ list: {
+ padding: 0,
+ },
+ tokenItemInnerDiv: {
+ paddingLeft: 60,
+ },
+ headerItemInnerDiv: {
+ paddingLeft: 65,
+ },
+ footerItemInnerDiv: {
+ paddingLeft: 24,
+ },
+ borderedItem: {
+ borderBottomColor: colors.walletBorder,
+ borderBottomStyle: 'solid',
+ borderWidth: 1,
+ },
+ tokenItem: {
+ backgroundColor: colors.walletDefaultItemBackground,
+ paddingTop: 8,
+ paddingBottom: 8,
+ },
+ headerItem: {
+ paddingTop: 8,
+ paddingBottom: 8,
+ },
+ wrappedEtherButtonLabel: {
+ fontSize: 12,
+ },
+ amountLabel: {
+ fontWeight: 'bold',
+ color: colors.black,
+ },
+};
+
+const ETHER_ICON_PATH = '/images/ether.png';
+const ETHER_TOKEN_SYMBOL = 'WETH';
+const ZRX_TOKEN_SYMBOL = 'ZRX';
+const ETHER_SYMBOL = 'ETH';
+const ICON_DIMENSION = 24;
+const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
+
+export class Wallet extends React.Component<WalletProps, WalletState> {
+ private _isUnmounted: boolean;
+ constructor(props: WalletProps) {
+ super(props);
+ this._isUnmounted = false;
+ const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens);
+ this.state = {
+ trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
+ };
+ }
+ public componentWillMount() {
+ const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
+ // tslint:disable-next-line:no-floating-promises
+ this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
+ }
+ public componentWillUnmount() {
+ this._isUnmounted = true;
+ }
+ public componentWillReceiveProps(nextProps: WalletProps) {
+ if (
+ nextProps.userAddress !== this.props.userAddress ||
+ nextProps.networkId !== this.props.networkId ||
+ nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch
+ ) {
+ const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
+ // tslint:disable-next-line:no-floating-promises
+ this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
+ }
+ if (!_.isEqual(nextProps.trackedTokens, this.props.trackedTokens)) {
+ const newTokens = _.difference(nextProps.trackedTokens, this.props.trackedTokens);
+ const newTokenAddresses = _.map(newTokens, token => token.address);
+ // Add placeholder entry for this token to the state, since fetching the
+ // balance/allowance is asynchronous
+ const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
+ _.each(newTokenAddresses, (tokenAddress: string) => {
+ trackedTokenStateByAddress[tokenAddress] = {
+ balance: new BigNumber(0),
+ allowance: new BigNumber(0),
+ isLoaded: false,
+ };
+ });
+ this.setState({
+ trackedTokenStateByAddress,
+ });
+ // Fetch the actual balance/allowance.
+ // tslint:disable-next-line:no-floating-promises
+ this._fetchBalancesAndAllowancesAsync(newTokenAddresses);
+ }
+ }
+ public render() {
+ const isReadyToRender = this.props.blockchainIsLoaded && this.props.blockchainErr === BlockchainErrs.NoError;
+ return <div style={styles.wallet}>{isReadyToRender && this._renderRows()}</div>;
+ }
+ private _renderRows() {
+ return (
+ <List style={styles.list}>
+ {_.concat(
+ this._renderHeaderRows(),
+ this._renderEthRows(),
+ this._renderTokenRows(),
+ this._renderFooterRows(),
+ )}
+ </List>
+ );
+ }
+ private _renderHeaderRows() {
+ const userAddress = this.props.userAddress;
+ const primaryText = utils.getAddressBeginAndEnd(userAddress);
+ return (
+ <ListItem
+ primaryText={primaryText}
+ leftIcon={<Identicon address={userAddress} diameter={ICON_DIMENSION} />}
+ style={{ ...styles.headerItem, ...styles.borderedItem }}
+ innerDivStyle={styles.headerItemInnerDiv}
+ />
+ );
+ }
+ private _renderFooterRows() {
+ const primaryText = '+ other tokens';
+ return (
+ <ListItem primaryText={primaryText} style={styles.borderedItem} innerDivStyle={styles.footerItemInnerDiv} />
+ );
+ }
+ private _renderEthRows() {
+ const primaryText = this._renderAmount(
+ this.props.userEtherBalanceInWei,
+ constants.DECIMAL_PLACES_ETH,
+ ETHER_SYMBOL,
+ );
+ const accessoryItemConfig = {
+ wrappedEtherAction: WrappedEtherAction.Wrap,
+ };
+ return (
+ <ListItem
+ primaryText={primaryText}
+ leftIcon={<img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />}
+ rightAvatar={this._renderAccessoryItems(accessoryItemConfig)}
+ style={{ ...styles.tokenItem, ...styles.borderedItem }}
+ innerDivStyle={styles.tokenItemInnerDiv}
+ />
+ );
+ }
+ private _renderTokenRows() {
+ const trackedTokens = this.props.trackedTokens;
+ const trackedTokensStartingWithEtherToken = trackedTokens.sort(
+ firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL)
+ .thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL)
+ .thenBy('address'),
+ );
+ return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
+ }
+ private _renderTokenRow(token: Token) {
+ const tokenState = this.state.trackedTokenStateByAddress[token.address];
+ const tokenLink = sharedUtils.getEtherScanLinkIfExists(
+ token.address,
+ this.props.networkId,
+ EtherscanLinkSuffixes.Address,
+ );
+ const amount = this._renderAmount(tokenState.balance, token.decimals, token.symbol);
+ const wrappedEtherAction = token.symbol === ETHER_TOKEN_SYMBOL ? WrappedEtherAction.Unwrap : undefined;
+ const accessoryItemConfig: AccessoryItemConfig = {
+ wrappedEtherAction,
+ allowanceToggleConfig: {
+ token,
+ tokenState,
+ },
+ };
+ return (
+ <ListItem
+ primaryText={amount}
+ leftIcon={this._renderTokenIcon(token, tokenLink)}
+ rightAvatar={this._renderAccessoryItems(accessoryItemConfig)}
+ style={{ ...styles.tokenItem, ...styles.borderedItem }}
+ innerDivStyle={styles.tokenItemInnerDiv}
+ />
+ );
+ }
+ private _renderAccessoryItems(config: AccessoryItemConfig) {
+ const shouldShowWrappedEtherAction = !_.isUndefined(config.wrappedEtherAction);
+ const shouldShowToggle = !_.isUndefined(config.allowanceToggleConfig);
+ return (
+ <div style={{ width: 160 }}>
+ <div className="flex">
+ <div className="flex-auto">
+ {shouldShowWrappedEtherAction && this._renderWrappedEtherButton(config.wrappedEtherAction)}
+ </div>
+ <div className="flex-last py1">
+ {shouldShowToggle && this._renderAllowanceToggle(config.allowanceToggleConfig)}
+ </div>
+ </div>
+ </div>
+ );
+ }
+ private _renderAllowanceToggle(config: AllowanceToggleConfig) {
+ return (
+ <AllowanceToggle
+ networkId={this.props.networkId}
+ blockchain={this.props.blockchain}
+ dispatcher={this.props.dispatcher}
+ token={config.token}
+ tokenState={config.tokenState}
+ onErrorOccurred={_.noop} // TODO: Error handling
+ userAddress={this.props.userAddress}
+ isDisabled={!config.tokenState.isLoaded}
+ refetchTokenStateAsync={this._refetchTokenStateAsync.bind(this, config.token.address)}
+ />
+ );
+ }
+ private _renderAmount(amount: BigNumber, decimals: number, symbol: string) {
+ const unitAmount = ZeroEx.toUnitAmount(amount, decimals);
+ const formattedAmount = unitAmount.toPrecision(TOKEN_AMOUNT_DISPLAY_PRECISION);
+ const result = `${formattedAmount} ${symbol}`;
+ return <div style={styles.amountLabel}>{result}</div>;
+ }
+ private _renderTokenIcon(token: Token, tokenLink?: string) {
+ const tooltipId = `tooltip-${token.address}`;
+ const tokenIcon = <TokenIcon token={token} diameter={ICON_DIMENSION} />;
+ if (_.isUndefined(tokenLink)) {
+ return tokenIcon;
+ } else {
+ return (
+ <a href={tokenLink} target="_blank" style={{ textDecoration: 'none' }}>
+ {tokenIcon}
+ </a>
+ );
+ }
+ }
+ private _renderWrappedEtherButton(action: WrappedEtherAction) {
+ let buttonLabel;
+ let buttonIcon;
+ switch (action) {
+ case WrappedEtherAction.Wrap:
+ buttonLabel = 'wrap';
+ buttonIcon = <NavigationArrowDownward />;
+ break;
+ case WrappedEtherAction.Unwrap:
+ buttonLabel = 'unwrap';
+ buttonIcon = <NavigationArrowUpward />;
+ break;
+ default:
+ throw utils.spawnSwitchErr('wrappedEtherAction', action);
+ }
+ return (
+ <FlatButton
+ label={buttonLabel}
+ labelPosition="after"
+ primary={true}
+ icon={buttonIcon}
+ labelStyle={styles.wrappedEtherButtonLabel}
+ />
+ );
+ }
+ private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]) {
+ const trackedTokenStateByAddress: TokenStateByAddress = {};
+ _.each(trackedTokens, token => {
+ trackedTokenStateByAddress[token.address] = {
+ balance: new BigNumber(0),
+ allowance: new BigNumber(0),
+ isLoaded: false,
+ };
+ });
+ return trackedTokenStateByAddress;
+ }
+ private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]) {
+ const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress;
+ const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
+ for (const tokenAddress of tokenAddresses) {
+ const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
+ userAddressIfExists,
+ tokenAddress,
+ );
+ trackedTokenStateByAddress[tokenAddress] = {
+ balance,
+ allowance,
+ isLoaded: true,
+ };
+ }
+ if (!this._isUnmounted) {
+ this.setState({
+ trackedTokenStateByAddress,
+ });
+ }
+ }
+ private async _refetchTokenStateAsync(tokenAddress: string) {
+ const userAddressIfExists = _.isEmpty(this.props.userAddress) ? undefined : this.props.userAddress;
+ const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync(
+ userAddressIfExists,
+ tokenAddress,
+ );
+ this.setState({
+ trackedTokenStateByAddress: {
+ ...this.state.trackedTokenStateByAddress,
+ [tokenAddress]: {
+ balance,
+ allowance,
+ isLoaded: true,
+ },
+ },
+ });
+ }
+}
diff --git a/packages/website/ts/containers/deployer_documentation.ts b/packages/website/ts/containers/deployer_documentation.ts
new file mode 100644
index 000000000..4e1c41f8c
--- /dev/null
+++ b/packages/website/ts/containers/deployer_documentation.ts
@@ -0,0 +1,102 @@
+import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { DocPackages, Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+/* tslint:disable:no-var-requires */
+const IntroMarkdown = require('md/docs/deployer/introduction');
+const InstallationMarkdown = require('md/docs/deployer/installation');
+const UsageMarkdown = require('md/docs/deployer/usage');
+/* tslint:enable:no-var-requires */
+
+const docSections = {
+ introduction: 'introduction',
+ installation: 'installation',
+ usage: 'usage',
+ compiler: 'compiler',
+ deployer: 'deployer',
+ types: docConstants.TYPES_SECTION_NAME,
+};
+
+const docsInfoConfig: DocsInfoConfig = {
+ id: DocPackages.Deployer,
+ type: SupportedDocJson.TypeDoc,
+ displayName: 'Deployer',
+ packageUrl: 'https://github.com/0xProject/0x-monorepo',
+ menu: {
+ introduction: [docSections.introduction],
+ install: [docSections.installation],
+ usage: [docSections.usage],
+ compiler: [docSections.compiler],
+ deployer: [docSections.deployer],
+ types: [docSections.types],
+ },
+ sectionNameToMarkdown: {
+ [docSections.introduction]: IntroMarkdown,
+ [docSections.installation]: InstallationMarkdown,
+ [docSections.usage]: UsageMarkdown,
+ },
+ sectionNameToModulePath: {
+ [docSections.compiler]: ['"deployer/src/compiler"'],
+ [docSections.deployer]: ['"deployer/src/deployer"'],
+ [docSections.types]: ['"deployer/src/utils/types"', '"types/src/index"'],
+ },
+ menuSubsectionToVersionWhenIntroduced: {},
+ sections: docSections,
+ visibleConstructors: [docSections.compiler, docSections.deployer],
+ typeConfigs: {
+ // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
+ // currently no way to extract the re-exported types from index.ts via TypeDoc :(
+ publicTypes: [
+ 'CompilerOptions',
+ 'DeployerOptions',
+ 'BaseDeployerOptions',
+ 'UrlDeployerOptions',
+ 'ProviderDeployerOptions',
+ 'TxData',
+ ],
+ typeNameToExternalLink: {
+ Web3: 'https://github.com/ethereum/wiki/wiki/JavaScript-API',
+ BigNumber: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127',
+ ContractInstance: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L98',
+ },
+ typeNameToPrefix: {
+ ContractInstance: 'Web3',
+ },
+ },
+};
+const docsInfo = new DocsInfo(docsInfoConfig);
+
+interface ConnectedState {
+ docsVersion: string;
+ availableDocVersions: string[];
+ docsInfo: DocsInfo;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({
+ docsVersion: state.docsVersion,
+ availableDocVersions: state.availableDocVersions,
+ translate: state.translate,
+ docsInfo,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Documentation: React.ComponentClass<DocPageProps> = connect(mapStateToProps, mapDispatchToProps)(
+ DocPageComponent,
+);
diff --git a/packages/website/ts/containers/json_schemas_documentation.ts b/packages/website/ts/containers/json_schemas_documentation.ts
new file mode 100644
index 000000000..154c65ffc
--- /dev/null
+++ b/packages/website/ts/containers/json_schemas_documentation.ts
@@ -0,0 +1,89 @@
+import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { DocPackages, Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+/* tslint:disable:no-var-requires */
+const IntroMarkdown = require('md/docs/json_schemas/introduction');
+const InstallationMarkdown = require('md/docs/json_schemas/installation');
+const UsageMarkdown = require('md/docs/json_schemas/usage');
+const SchemasMarkdown = require('md/docs/json_schemas/schemas');
+/* tslint:enable:no-var-requires */
+
+const docSections = {
+ introduction: 'introduction',
+ installation: 'installation',
+ usage: 'usage',
+ schemaValidator: 'schemaValidator',
+ schemas: 'schemas',
+};
+
+const docsInfoConfig: DocsInfoConfig = {
+ id: DocPackages.JSONSchemas,
+ type: SupportedDocJson.TypeDoc,
+ displayName: 'JSON Schemas',
+ packageUrl: 'https://github.com/0xProject/0x-monorepo',
+ menu: {
+ introduction: [docSections.introduction],
+ install: [docSections.installation],
+ usage: [docSections.usage],
+ schemaValidator: [docSections.schemaValidator],
+ schemas: [docSections.schemas],
+ },
+ sectionNameToMarkdown: {
+ [docSections.introduction]: IntroMarkdown,
+ [docSections.installation]: InstallationMarkdown,
+ [docSections.schemas]: SchemasMarkdown,
+ [docSections.usage]: UsageMarkdown,
+ },
+ sectionNameToModulePath: {
+ [docSections.schemaValidator]: ['"json-schemas/src/schema_validator"'],
+ },
+ menuSubsectionToVersionWhenIntroduced: {},
+ sections: docSections,
+ visibleConstructors: [docSections.schemaValidator],
+ typeConfigs: {
+ // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
+ // currently no way to extract the re-exported types from index.ts via TypeDoc :(
+ publicTypes: [],
+ typeNameToExternalLink: {
+ Schema:
+ 'https://github.com/tdegrunt/jsonschema/blob/5c2edd4baba149964aec0f23c87ad12c25a50dfb/lib/index.d.ts#L49',
+ },
+ },
+};
+const docsInfo = new DocsInfo(docsInfoConfig);
+
+interface ConnectedState {
+ docsVersion: string;
+ availableDocVersions: string[];
+ docsInfo: DocsInfo;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({
+ docsVersion: state.docsVersion,
+ availableDocVersions: state.availableDocVersions,
+ translate: state.translate,
+ docsInfo,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Documentation: React.ComponentClass<DocPageProps> = connect(mapStateToProps, mapDispatchToProps)(
+ DocPageComponent,
+);
diff --git a/packages/website/ts/containers/sol_cov_documentation.ts b/packages/website/ts/containers/sol_cov_documentation.ts
new file mode 100644
index 000000000..2b901ec6f
--- /dev/null
+++ b/packages/website/ts/containers/sol_cov_documentation.ts
@@ -0,0 +1,89 @@
+import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { DocPackages, Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+/* tslint:disable:no-var-requires */
+const IntroMarkdown = require('md/docs/sol_cov/introduction');
+const InstallationMarkdown = require('md/docs/sol_cov/installation');
+const UsageMarkdown = require('md/docs/sol_cov/usage');
+/* tslint:enable:no-var-requires */
+
+const docSections = {
+ introduction: 'introduction',
+ installation: 'installation',
+ usage: 'usage',
+ coverageSubprovider: 'coverageSubprovider',
+ types: docConstants.TYPES_SECTION_NAME,
+};
+
+const docsInfoConfig: DocsInfoConfig = {
+ id: DocPackages.SolCov,
+ type: SupportedDocJson.TypeDoc,
+ displayName: 'Sol-cov',
+ packageUrl: 'https://github.com/0xProject/0x-monorepo',
+ menu: {
+ introduction: [docSections.introduction],
+ install: [docSections.installation],
+ usage: [docSections.usage],
+ coverageSubprovider: [docSections.coverageSubprovider],
+ types: [docSections.types],
+ },
+ sectionNameToMarkdown: {
+ [docSections.introduction]: IntroMarkdown,
+ [docSections.installation]: InstallationMarkdown,
+ [docSections.usage]: UsageMarkdown,
+ },
+ sectionNameToModulePath: {
+ [docSections.coverageSubprovider]: ['"sol-cov/src/coverage_subprovider"'],
+ [docSections.types]: ['"subproviders/src/types"'],
+ },
+ menuSubsectionToVersionWhenIntroduced: {},
+ sections: docSections,
+ visibleConstructors: [docSections.coverageSubprovider],
+ typeConfigs: {
+ // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
+ // currently no way to extract the re-exported types from index.ts via TypeDoc :(
+ publicTypes: ['NextCallback', 'OnNextCompleted', 'ErrorCallback'],
+ typeNameToExternalLink: {},
+ typeNameToPrefix: {
+ JSONRPCRequestPayload: 'Web3',
+ },
+ typeNameToDocSection: {},
+ },
+};
+const docsInfo = new DocsInfo(docsInfoConfig);
+
+interface ConnectedState {
+ docsVersion: string;
+ availableDocVersions: string[];
+ docsInfo: DocsInfo;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({
+ docsVersion: state.docsVersion,
+ availableDocVersions: state.availableDocVersions,
+ translate: state.translate,
+ docsInfo,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Documentation: React.ComponentClass<DocPageProps> = connect(mapStateToProps, mapDispatchToProps)(
+ DocPageComponent,
+);
diff --git a/packages/website/ts/containers/subproviders_documentation.ts b/packages/website/ts/containers/subproviders_documentation.ts
new file mode 100644
index 000000000..7aa05f9a5
--- /dev/null
+++ b/packages/website/ts/containers/subproviders_documentation.ts
@@ -0,0 +1,141 @@
+import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { DocPackages, Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+/* tslint:disable:no-var-requires */
+const IntroMarkdown = require('md/docs/subproviders/introduction');
+const InstallationMarkdown = require('md/docs/subproviders/installation');
+const LedgerNodeHidMarkdown = require('md/docs/subproviders/ledger_node_hid');
+/* tslint:enable:no-var-requires */
+
+const docSections = {
+ introduction: 'introduction',
+ installation: 'installation',
+ subprovider: 'subprovider',
+ ledgerSubprovider: 'ledgerSubprovider',
+ ledgerNodeHid: 'ledger-node-hid-issue',
+ factoryMethods: 'factory-methods',
+ emptyWalletSubprovider: 'emptyWalletSubprovider',
+ fakeGasEstimateSubprovider: 'fakeGasEstimateSubprovider',
+ injectedWeb3Subprovider: 'injectedWeb3Subprovider',
+ redundantRPCSubprovider: 'redundantRPCSubprovider',
+ ganacheSubprovider: 'ganacheSubprovider',
+ nonceTrackerSubprovider: 'nonceTrackerSubprovider',
+ types: docConstants.TYPES_SECTION_NAME,
+};
+
+const docsInfoConfig: DocsInfoConfig = {
+ id: DocPackages.Subproviders,
+ type: SupportedDocJson.TypeDoc,
+ displayName: 'Subproviders',
+ packageUrl: 'https://github.com/0xProject/0x-monorepo',
+ menu: {
+ introduction: [docSections.introduction],
+ install: [docSections.installation],
+ subprovider: [docSections.subprovider],
+ ['ledger-subprovider']: [docSections.ledgerSubprovider],
+ ['ledger-node-hid-issue']: [docSections.ledgerNodeHid],
+ ['factory-methods']: [docSections.factoryMethods],
+ ['emptyWallet-subprovider']: [docSections.emptyWalletSubprovider],
+ ['fakeGasEstimate-subprovider']: [docSections.fakeGasEstimateSubprovider],
+ ['injectedWeb3-subprovider']: [docSections.injectedWeb3Subprovider],
+ ['redundantRPC-subprovider']: [docSections.redundantRPCSubprovider],
+ ['ganache-subprovider']: [docSections.ganacheSubprovider],
+ ['nonceTracker-subprovider']: [docSections.nonceTrackerSubprovider],
+ types: [docSections.types],
+ },
+ sectionNameToMarkdown: {
+ [docSections.introduction]: IntroMarkdown,
+ [docSections.installation]: InstallationMarkdown,
+ [docSections.ledgerNodeHid]: LedgerNodeHidMarkdown,
+ },
+ sectionNameToModulePath: {
+ [docSections.subprovider]: ['"subproviders/src/subproviders/subprovider"'],
+ [docSections.ledgerSubprovider]: ['"subproviders/src/subproviders/ledger"'],
+ [docSections.factoryMethods]: ['"subproviders/src/index"'],
+ [docSections.emptyWalletSubprovider]: ['"subproviders/src/subproviders/empty_wallet_subprovider"'],
+ [docSections.fakeGasEstimateSubprovider]: ['"subproviders/src/subproviders/fake_gas_estimate_subprovider"'],
+ [docSections.injectedWeb3Subprovider]: ['"subproviders/src/subproviders/injected_web3"'],
+ [docSections.redundantRPCSubprovider]: ['"subproviders/src/subproviders/redundant_rpc"'],
+ [docSections.ganacheSubprovider]: ['"subproviders/src/subproviders/ganache"'],
+ [docSections.nonceTrackerSubprovider]: ['"subproviders/src/subproviders/nonce_tracker"'],
+ [docSections.types]: ['"deployer/src/utils/types"', '"types/src/index"', '"subproviders/src/types"'],
+ },
+ menuSubsectionToVersionWhenIntroduced: {},
+ sections: docSections,
+ visibleConstructors: [
+ docSections.subprovider,
+ docSections.ledgerSubprovider,
+ docSections.emptyWalletSubprovider,
+ docSections.fakeGasEstimateSubprovider,
+ docSections.injectedWeb3Subprovider,
+ docSections.redundantRPCSubprovider,
+ docSections.ganacheSubprovider,
+ docSections.nonceTrackerSubprovider,
+ ],
+ typeConfigs: {
+ // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
+ // currently no way to extract the re-exported types from index.ts via TypeDoc :(
+ publicTypes: [
+ 'Callback',
+ 'NextCallback',
+ 'ErrorCallback',
+ 'ECSignature',
+ 'JSONRPCRequestPayloadWithMethod',
+ 'JSONRPCResponsePayload',
+ 'AccountFetchingConfigs',
+ 'LedgerEthereumClientFactoryAsync',
+ 'PartialTxParams',
+ 'LedgerEthereumClient',
+ 'LedgerSubproviderConfigs',
+ ],
+ typeNameToExternalLink: {
+ Web3: 'https://github.com/ethereum/wiki/wiki/JavaScript-API',
+ BigNumber: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127',
+ JSONRPCRequestPayload: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L137',
+ JSONRPCResponsePayload: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L144',
+ Provider: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L150',
+ },
+ typeNameToPrefix: {
+ JSONRPCRequestPayload: 'Web3',
+ JSONRPCResponsePayload: 'Web3',
+ Provider: 'Web3',
+ },
+ },
+};
+const docsInfo = new DocsInfo(docsInfoConfig);
+
+interface ConnectedState {
+ docsVersion: string;
+ availableDocVersions: string[];
+ docsInfo: DocsInfo;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({
+ docsVersion: state.docsVersion,
+ availableDocVersions: state.availableDocVersions,
+ translate: state.translate,
+ docsInfo,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Documentation: React.ComponentClass<DocPageProps> = connect(mapStateToProps, mapDispatchToProps)(
+ DocPageComponent,
+);
diff --git a/packages/website/ts/containers/web3_wrapper_documentation.ts b/packages/website/ts/containers/web3_wrapper_documentation.ts
new file mode 100644
index 000000000..0a0911b80
--- /dev/null
+++ b/packages/website/ts/containers/web3_wrapper_documentation.ts
@@ -0,0 +1,103 @@
+import { constants as docConstants, DocsInfo, DocsInfoConfig, SupportedDocJson } from '@0xproject/react-docs';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { DocPackages, Environments, WebsitePaths } from 'ts/types';
+import { configs } from 'ts/utils/configs';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+/* tslint:disable:no-var-requires */
+const IntroMarkdown = require('md/docs/web3_wrapper/introduction');
+const InstallationMarkdown = require('md/docs/web3_wrapper/installation');
+/* tslint:enable:no-var-requires */
+
+const docSections = {
+ introduction: 'introduction',
+ installation: 'installation',
+ web3Wrapper: 'web3Wrapper',
+ types: docConstants.TYPES_SECTION_NAME,
+};
+
+const docsInfoConfig: DocsInfoConfig = {
+ id: DocPackages.Web3Wrapper,
+ type: SupportedDocJson.TypeDoc,
+ displayName: 'Web3Wrapper',
+ packageUrl: 'https://github.com/0xProject/0x-monorepo',
+ menu: {
+ introduction: [docSections.introduction],
+ install: [docSections.installation],
+ web3Wrapper: [docSections.web3Wrapper],
+ types: [docSections.types],
+ },
+ sectionNameToMarkdown: {
+ [docSections.introduction]: IntroMarkdown,
+ [docSections.installation]: InstallationMarkdown,
+ },
+ sectionNameToModulePath: {
+ [docSections.web3Wrapper]: ['"web3-wrapper/src/index"'],
+ [docSections.types]: ['"types/src/index"'],
+ },
+ menuSubsectionToVersionWhenIntroduced: {},
+ sections: docSections,
+ visibleConstructors: [docSections.web3Wrapper],
+ typeConfigs: {
+ // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is
+ // currently no way to extract the re-exported types from index.ts via TypeDoc :(
+ publicTypes: ['TxData', 'TransactionReceipt', 'RawLogEntry'],
+ typeNameToExternalLink: {
+ Web3: 'https://github.com/ethereum/wiki/wiki/JavaScript-API',
+ Provider: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L150',
+ BigNumber: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127',
+ LogEntryEvent: 'http://mikemcl.github.io/bignumber.js',
+ CallData: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L348',
+ BlockWithoutTransactionData:
+ 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L314',
+ LogEntry: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L366',
+ FilterObject: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L109',
+ ['Web3.BlockParam']: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L278',
+ ['Web3.ContractAbi']: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L47',
+ },
+ typeNameToPrefix: {
+ Provider: 'Web3',
+ CallData: 'Web3',
+ BlockWithoutTransactionData: 'Web3',
+ LogEntry: 'Web3',
+ FilterObject: 'Web3',
+ },
+ typeNameToDocSection: {
+ Web3Wrapper: docSections.web3Wrapper,
+ },
+ },
+};
+const docsInfo = new DocsInfo(docsInfoConfig);
+
+interface ConnectedState {
+ docsVersion: string;
+ availableDocVersions: string[];
+ docsInfo: DocsInfo;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: DocPageProps): ConnectedState => ({
+ docsVersion: state.docsVersion,
+ availableDocVersions: state.availableDocVersions,
+ translate: state.translate,
+ docsInfo,
+});
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Documentation: React.ComponentClass<DocPageProps> = connect(mapStateToProps, mapDispatchToProps)(
+ DocPageComponent,
+);
diff --git a/packages/website/ts/containers/zero_ex_js_documentation.ts b/packages/website/ts/containers/zero_ex_js_documentation.ts
index ec30780c3..6e893133f 100644
--- a/packages/website/ts/containers/zero_ex_js_documentation.ts
+++ b/packages/website/ts/containers/zero_ex_js_documentation.ts
@@ -90,7 +90,14 @@ const docsInfoConfig: DocsInfoConfig = {
'"0x.js/src/order_watcher/order_state_watcher"',
'"src/order_watcher/order_state_watcher"',
],
- [zeroExJsDocSections.types]: ['"0x.js/src/types"', '"src/types"', '"types/src/index"'],
+ [zeroExJsDocSections.types]: [
+ '"0x.js/src/types"',
+ '"src/types"',
+ '"types/src/index"',
+ '"0x.js/src/contract_wrappers/generated/ether_token"',
+ '"0x.js/src/contract_wrappers/generated/token"',
+ '"0x.js/src/contract_wrappers/generated/exchange"',
+ ],
},
menuSubsectionToVersionWhenIntroduced: {
[zeroExJsDocSections.etherToken]: '0.7.1',
@@ -151,7 +158,6 @@ const docsInfoConfig: DocsInfoConfig = {
'TransactionOpts',
'ContractEventArg',
'LogEvent',
- 'LogEntry',
'DecodedLogEvent',
'EventWatcherCallback',
'OnOrderStateChangeCallback',
@@ -167,6 +173,7 @@ const docsInfoConfig: DocsInfoConfig = {
DecodedLogEntryEvent: 'Web3',
LogEntryEvent: 'Web3',
CallData: 'Web3',
+ LogEntry: 'Web3',
},
typeNameToExternalLink: {
Web3: constants.URL_WEB3_DOCS,
@@ -174,6 +181,7 @@ const docsInfoConfig: DocsInfoConfig = {
BigNumber: constants.URL_BIGNUMBERJS_GITHUB,
DecodedLogEntryEvent: constants.URL_WEB3_DECODED_LOG_ENTRY_EVENT,
LogEntryEvent: constants.URL_WEB3_LOG_ENTRY_EVENT,
+ LogEntry: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L366',
},
typeNameToDocSection: {
ExchangeWrapper: 'exchange',
diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx
index b24517e39..d542bd804 100644
--- a/packages/website/ts/index.tsx
+++ b/packages/website/ts/index.tsx
@@ -45,6 +45,21 @@ const LazySmartContractsDocumentation = createLazyComponent('Documentation', asy
const LazyConnectDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "connectDocs" */ 'ts/containers/connect_documentation'),
);
+const LazyWeb3WrapperDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "web3WrapperDocs" */ 'ts/containers/web3_wrapper_documentation'),
+);
+const LazyDeployerDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "deployerDocs" */ 'ts/containers/deployer_documentation'),
+);
+const LazyJSONSchemasDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "jsonSchemasDocs" */ 'ts/containers/json_schemas_documentation'),
+);
+const LazySolCovDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "solCovDocs" */ 'ts/containers/sol_cov_documentation'),
+);
+const LazySubprovidersDocumentation = createLazyComponent('Documentation', async () =>
+ System.import<any>(/* webpackChunkName: "subproviderDocs" */ 'ts/containers/subproviders_documentation'),
+);
analytics.init();
// tslint:disable-next-line:no-floating-promises
@@ -65,6 +80,20 @@ render(
<Route path={`${WebsitePaths.Wiki}`} component={Wiki as any} />
<Route path={`${WebsitePaths.ZeroExJs}/:version?`} component={LazyZeroExJSDocumentation} />
<Route path={`${WebsitePaths.Connect}/:version?`} component={LazyConnectDocumentation} />
+ <Route path={`${WebsitePaths.Deployer}/:version?`} component={LazyDeployerDocumentation} />
+ <Route path={`${WebsitePaths.SolCov}/:version?`} component={LazySolCovDocumentation} />
+ <Route
+ path={`${WebsitePaths.JSONSchemas}/:version?`}
+ component={LazyJSONSchemasDocumentation}
+ />
+ <Route
+ path={`${WebsitePaths.Subproviders}/:version?`}
+ component={LazySubprovidersDocumentation}
+ />
+ <Route
+ path={`${WebsitePaths.Web3Wrapper}/:version?`}
+ component={LazyWeb3WrapperDocumentation}
+ />
<Route
path={`${WebsitePaths.SmartContracts}/:version?`}
component={LazySmartContractsDocumentation}
diff --git a/packages/website/ts/pages/documentation/doc_page.tsx b/packages/website/ts/pages/documentation/doc_page.tsx
index 1281219c6..8ec1a023d 100644
--- a/packages/website/ts/pages/documentation/doc_page.tsx
+++ b/packages/website/ts/pages/documentation/doc_page.tsx
@@ -15,19 +15,25 @@ import { docUtils } from 'ts/utils/doc_utils';
import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils';
+const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT;
+const DEFAULT_ICON = 'docs.png';
const ZERO_EX_JS_VERSION_MISSING_TOPLEVEL_PATH = '0.32.4';
-const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT;
-const docIdToS3BucketName: { [id: string]: string } = {
- [DocPackages.ZeroExJs]: isDevelopment ? 'staging-0xjs-docs-jsons' : '0xjs-docs-jsons',
- [DocPackages.SmartContracts]: 'smart-contracts-docs-json',
- [DocPackages.Connect]: isDevelopment ? 'staging-connect-docs-jsons' : 'connect-docs-jsons',
+const idToIcon: { [id: string]: string } = {
+ [DocPackages.ZeroExJs]: 'zeroExJs.png',
+ [DocPackages.Connect]: 'connect.png',
+ [DocPackages.SmartContracts]: 'contracts.png',
};
const docIdToSubpackageName: { [id: string]: string } = {
[DocPackages.ZeroExJs]: '0x.js',
[DocPackages.Connect]: 'connect',
[DocPackages.SmartContracts]: 'contracts',
+ [DocPackages.Web3Wrapper]: 'web3-wrapper',
+ [DocPackages.Deployer]: 'deployer',
+ [DocPackages.JSONSchemas]: 'json-schemas',
+ [DocPackages.SolCov]: 'sol-cov',
+ [DocPackages.Subproviders]: 'subproviders',
};
export interface DocPageProps {
@@ -63,12 +69,13 @@ export class DocPage extends React.Component<DocPageProps, DocPageState> {
public componentWillUnmount() {
this._isUnmounted = true;
}
-
public render() {
const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat)
? {}
: this.props.docsInfo.getMenuSubsectionsBySection(this.state.docAgnosticFormat);
const sourceUrl = this._getSourceUrl();
+ const iconFileName = idToIcon[this.props.docsInfo.id] || DEFAULT_ICON;
+ const iconUrl = `/images/doc_icons/${iconFileName}`;
return (
<div>
<DocumentTitle title={`${this.props.docsInfo.displayName} Documentation`} />
@@ -82,13 +89,14 @@ export class DocPage extends React.Component<DocPageProps, DocPageState> {
docsInfo={this.props.docsInfo}
translate={this.props.translate}
onVersionSelected={this._onVersionSelected.bind(this)}
+ sidebarHeader={<SidebarHeader title={this.props.docsInfo.displayName} iconUrl={iconUrl} />}
/>
<Documentation
selectedVersion={this.props.docsVersion}
availableVersions={this.props.availableDocVersions}
docsInfo={this.props.docsInfo}
docAgnosticFormat={this.state.docAgnosticFormat}
- sidebarHeader={<SidebarHeader title={this.props.docsInfo.displayName} />}
+ sidebarHeader={<SidebarHeader title={this.props.docsInfo.displayName} iconUrl={iconUrl} />}
sourceUrl={sourceUrl}
topBarHeight={60}
onVersionSelected={this._onVersionSelected.bind(this)}
@@ -97,25 +105,25 @@ export class DocPage extends React.Component<DocPageProps, DocPageState> {
);
}
private async _fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> {
- const s3BucketName = docIdToS3BucketName[this.props.docsInfo.id];
- const docsJsonRoot = `${constants.S3_BUCKET_ROOT}/${s3BucketName}`;
- const versionToFileName = await docUtils.getVersionToFileNameAsync(docsJsonRoot);
- const versions = _.keys(versionToFileName);
+ const folderName = docIdToSubpackageName[this.props.docsInfo.id];
+ const docBucketRoot = isDevelopment ? constants.S3_STAGING_DOC_BUCKET_ROOT : constants.S3_DOC_BUCKET_ROOT;
+ const versionToFilePath = await docUtils.getVersionToFilePathAsync(docBucketRoot, folderName);
+ const versions = _.keys(versionToFilePath);
this.props.dispatcher.updateAvailableDocVersions(versions);
const sortedVersions = semverSort.desc(versions);
const latestVersion = sortedVersions[0];
let versionToFetch = latestVersion;
if (!_.isUndefined(preferredVersionIfExists)) {
- const preferredVersionFileNameIfExists = versionToFileName[preferredVersionIfExists];
+ const preferredVersionFileNameIfExists = versionToFilePath[preferredVersionIfExists];
if (!_.isUndefined(preferredVersionFileNameIfExists)) {
versionToFetch = preferredVersionIfExists;
}
}
this.props.dispatcher.updateCurrentDocsVersion(versionToFetch);
- const versionFileNameToFetch = versionToFileName[versionToFetch];
- const versionDocObj = await docUtils.getJSONDocFileAsync(versionFileNameToFetch, docsJsonRoot);
+ const versionFilePathToFetch = versionToFilePath[versionToFetch];
+ const versionDocObj = await docUtils.getJSONDocFileAsync(versionFilePathToFetch, docBucketRoot);
const docAgnosticFormat = this.props.docsInfo.convertToDocAgnosticFormat(versionDocObj);
if (!this._isUnmounted) {
diff --git a/packages/website/ts/pages/faq/faq.tsx b/packages/website/ts/pages/faq/faq.tsx
index 1be3c3565..701031d44 100644
--- a/packages/website/ts/pages/faq/faq.tsx
+++ b/packages/website/ts/pages/faq/faq.tsx
@@ -238,8 +238,8 @@ const sections: FAQSection[] = [
answer: <div>1,000,000,000 ZRX. Fixed supply.</div>,
},
{
- prompt: 'When is the Token Launch? will there be a pre-sale?',
- answer: <div>The token launch will be on August 15th, 2017. There will not be a pre-sale.</div>,
+ prompt: 'When was the token launch? Was there a pre-sale?',
+ answer: <div>The token launch was on August 15th, 2017. There was no pre-sale.</div>,
},
{
prompt: 'What will the token launch proceeds be used for?',
diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx
index 6699e4e6f..c943e3d79 100644
--- a/packages/website/ts/pages/landing/landing.tsx
+++ b/packages/website/ts/pages/landing/landing.tsx
@@ -40,8 +40,8 @@ const THROTTLE_TIMEOUT = 100;
const relayersAndDappProjects: Project[] = [
{
- logoFileName: 'ethfinex.png',
- projectUrl: constants.PROJECT_URL_ETHFINEX,
+ logoFileName: 'ercdex.png',
+ projectUrl: constants.PROJECT_URL_ERC_DEX,
},
{
logoFileName: 'radar_relay.png',
@@ -60,6 +60,10 @@ const relayersAndDappProjects: Project[] = [
projectUrl: constants.PROJECT_URL_DYDX,
},
{
+ logoFileName: 'ethfinex.png',
+ projectUrl: constants.PROJECT_URL_ETHFINEX,
+ },
+ {
logoFileName: 'melonport.png',
projectUrl: constants.PROJECT_URL_MELONPORT,
},
@@ -99,10 +103,6 @@ const relayersAndDappProjects: Project[] = [
logoFileName: 'anx.png',
projectUrl: constants.PROJECT_URL_OPEN_ANX,
},
- {
- logoFileName: 'auctus.png',
- projectUrl: constants.PROJECT_URL_AUCTUS,
- },
];
const relayerProjects: Project[] = [
diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx
index e2dd3a68e..23d1b52fb 100644
--- a/packages/website/ts/pages/wiki/wiki.tsx
+++ b/packages/website/ts/pages/wiki/wiki.tsx
@@ -88,6 +88,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
...styles.mainContainers,
overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden',
};
+ const sidebarHeader = <SidebarHeader title="Wiki" iconUrl="/images/doc_icons/wiki.png" />;
return (
<div>
<DocumentTitle title="0x Protocol Wiki" />
@@ -96,6 +97,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
location={this.props.location}
menuSubsectionsBySection={menuSubsectionsBySection}
translate={this.props.translate}
+ sidebarHeader={sidebarHeader}
/>
{_.isUndefined(this.state.articlesBySection) ? (
<div className="col col-12" style={mainContainersStyle}>
@@ -134,7 +136,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
<NestedSidebarMenu
topLevelMenu={menuSubsectionsBySection}
menuSubsectionsBySection={menuSubsectionsBySection}
- sidebarHeader={<SidebarHeader title="Wiki" />}
+ sidebarHeader={sidebarHeader}
/>
</div>
</div>
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index b3e4973fa..104d2e50f 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -21,11 +21,6 @@ export interface TokenByAddress {
[address: string]: Token;
}
-export interface TokenState {
- allowance: BigNumber;
- balance: BigNumber;
-}
-
export interface AssetToken {
address?: string;
amount?: BigNumber;
@@ -336,7 +331,7 @@ export enum TokenVisibility {
TRACKED = 'TRACKED',
}
-export interface VersionToFileName {
+export interface VersionToFilePath {
[version: string]: string;
}
@@ -355,45 +350,22 @@ export enum WebsitePaths {
Whitepaper = '/pdfs/0x_white_paper.pdf',
SmartContracts = '/docs/contracts',
Connect = '/docs/connect',
+ Web3Wrapper = '/docs/web3_wrapper',
+ Deployer = '/docs/deployer',
+ JSONSchemas = '/docs/json-schemas',
+ SolCov = '/docs/sol-cov',
+ Subproviders = '/docs/subproviders',
}
export enum DocPackages {
Connect = 'CONNECT',
ZeroExJs = 'ZERO_EX_JS',
SmartContracts = 'SMART_CONTRACTS',
-}
-
-export interface TimestampMsRange {
- startTimestampMs: number;
- endTimestampMs: number;
-}
-
-export interface OutdatedWrappedEtherByNetworkId {
- [networkId: number]: {
- address: string;
- timestampMsRange: TimestampMsRange;
- };
-}
-
-export enum SmartContractDocSections {
- Introduction = 'Introduction',
- Exchange = 'Exchange',
- TokenTransferProxy = 'TokenTransferProxy',
- TokenRegistry = 'TokenRegistry',
- ZRXToken = 'ZRXToken',
-}
-
-export interface MaterialUIPosition {
- vertical: 'bottom' | 'top' | 'center';
- horizontal: 'left' | 'middle' | 'right';
-}
-
-export enum Language {
- English = 'EN',
- Spanish = 'ES',
- Chinese = 'ZH',
- Korean = 'KO',
- Russian = 'RU',
+ Web3Wrapper = 'WEB3_WRAPPER',
+ Deployer = 'DEPLOYER',
+ JSONSchemas = 'JSON_SCHEMAS',
+ SolCov = 'SOL_COV',
+ Subproviders = 'SUBPROVIDERS',
}
export enum Key {
@@ -442,11 +414,16 @@ export enum Key {
About = 'ABOUT',
Careers = 'CAREERS',
Contact = 'CONTACT',
+ Deployer = 'DEPLOYER',
+ JsonSchemas = 'JSON_SCHEMAS',
+ SolCov = 'SOL_COV',
+ Subproviders = 'SUBPROVIDERS',
Blog = 'BLOG',
Forum = 'FORUM',
Connect = 'CONNECT',
Whitepaper = 'WHITEPAPER',
Wiki = 'WIKI',
+ Web3Wrapper = 'WEB3_WRAPPER',
And = 'AND',
Faq = 'FAQ',
SmartContracts = 'SMART_CONTRACTS',
@@ -458,15 +435,58 @@ export enum Key {
RocketChat = 'ROCKETCHAT',
}
+export enum SmartContractDocSections {
+ Introduction = 'Introduction',
+ Exchange = 'Exchange',
+ TokenTransferProxy = 'TokenTransferProxy',
+ TokenRegistry = 'TokenRegistry',
+ ZRXToken = 'ZRXToken',
+}
+
+export enum Language {
+ English = 'EN',
+ Spanish = 'ES',
+ Chinese = 'ZH',
+ Korean = 'KO',
+ Russian = 'RU',
+}
+
export enum Deco {
Cap,
CapWords,
Upper,
}
+export interface MaterialUIPosition {
+ vertical: 'bottom' | 'top' | 'center';
+ horizontal: 'left' | 'middle' | 'right';
+}
+
export enum Providers {
Parity = 'PARITY',
Metamask = 'METAMASK',
Mist = 'MIST',
}
+
+export interface TimestampMsRange {
+ startTimestampMs: number;
+ endTimestampMs: number;
+}
+
+export interface OutdatedWrappedEtherByNetworkId {
+ [networkId: number]: {
+ address: string;
+ timestampMsRange: TimestampMsRange;
+ };
+}
+
+export interface TokenStateByAddress {
+ [address: string]: TokenState;
+}
+
+export interface TokenState {
+ balance: BigNumber;
+ allowance: BigNumber;
+ isLoaded: boolean;
+}
// tslint:disable:max-file-line-count
diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts
index f63e8617e..0584938eb 100644
--- a/packages/website/ts/utils/constants.ts
+++ b/packages/website/ts/utils/constants.ts
@@ -29,12 +29,13 @@ export const constants = {
PROVIDER_NAME_GENERIC: 'Injected Web3',
PROVIDER_NAME_PUBLIC: '0x Public',
ROLLBAR_ACCESS_TOKEN: 'a6619002b51c4464928201e6ea94de65',
- S3_BUCKET_ROOT: 'https://s3.amazonaws.com',
+ S3_DOC_BUCKET_ROOT: 'https://s3.amazonaws.com/doc-jsons',
+ S3_STAGING_DOC_BUCKET_ROOT: 'https://s3.amazonaws.com/staging-doc-jsons',
SUCCESS_STATUS: 200,
UNAVAILABLE_STATUS: 503,
TAKER_FEE: new BigNumber(0),
TESTNET_NAME: 'Kovan',
- PROJECT_URL_ETHFINEX: 'https://www.bitfinex.com/ethfinex',
+ PROJECT_URL_ETHFINEX: 'https://www.ethfinex.com/',
PROJECT_URL_AMADEUS: 'http://amadeusrelay.org',
PROJECT_URL_DDEX: 'https://ddex.io',
PROJECT_URL_DECENT_EX: 'https://decent.exchange',
diff --git a/packages/website/ts/utils/doc_utils.ts b/packages/website/ts/utils/doc_utils.ts
index 6b3f5f378..2a599bcbe 100644
--- a/packages/website/ts/utils/doc_utils.ts
+++ b/packages/website/ts/utils/doc_utils.ts
@@ -2,21 +2,21 @@ import { DoxityDocObj, TypeDocNode } from '@0xproject/react-docs';
import { logUtils } from '@0xproject/utils';
import findVersions = require('find-versions');
import * as _ from 'lodash';
-import { S3FileObject, VersionToFileName } from 'ts/types';
+import { S3FileObject, VersionToFilePath } from 'ts/types';
import { utils } from 'ts/utils/utils';
import convert = require('xml-js');
export const docUtils = {
- async getVersionToFileNameAsync(s3DocJsonRoot: string): Promise<VersionToFileName> {
- const versionFileNames = await this.getVersionFileNamesAsync(s3DocJsonRoot);
- const versionToFileName: VersionToFileName = {};
- _.each(versionFileNames, fileName => {
- const [version] = findVersions(fileName);
- versionToFileName[version] = fileName;
+ async getVersionToFilePathAsync(s3DocJsonRoot: string, folderName: string): Promise<VersionToFilePath> {
+ const versionFilePaths = await this.getVersionFileNamesAsync(s3DocJsonRoot, folderName);
+ const versionToFilePath: VersionToFilePath = {};
+ _.each(versionFilePaths, filePath => {
+ const [version] = findVersions(filePath);
+ versionToFilePath[version] = filePath;
});
- return versionToFileName;
+ return versionToFilePath;
},
- async getVersionFileNamesAsync(s3DocJsonRoot: string): Promise<string[]> {
+ async getVersionFileNamesAsync(s3DocJsonRoot: string, folderName: string): Promise<string[]> {
const response = await fetch(s3DocJsonRoot);
if (response.status !== 200) {
// TODO: Show the user an error message when the docs fail to load
@@ -33,13 +33,47 @@ export const docUtils = {
? (responseObj.ListBucketResult.Contents as S3FileObject[])
: [responseObj.ListBucketResult.Contents];
- const versionFileNames = _.map(fileObjs, fileObj => {
+ /*
+ * S3 simply pre-fixes files in "folders" with the folder name. Thus, since we
+ * store docJSONs for multiple packages in a single S3 bucket, we must filter out
+ * the versionFileNames for a given folder here (ignoring folder entries)
+ *
+ * Example S3 response:
+ * <ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ * <Name>staging-doc-jsons</Name>
+ * <Prefix/>
+ * <Marker/>
+ * <MaxKeys>1000</MaxKeys>
+ * <IsTruncated>false</IsTruncated>
+ * <Contents>
+ * <Key>0xjs/</Key>
+ * <LastModified>2018-03-16T13:17:46.000Z</LastModified>
+ * <ETag>"d41d8cd98f00b204e9800998ecf8427e"</ETag>
+ * <Size>0</Size>
+ * <StorageClass>STANDARD</StorageClass>
+ * </Contents>
+ * <Contents>
+ * <Key>0xjs/v0.1.0.json</Key>
+ * <LastModified>2018-03-16T13:18:23.000Z</LastModified>
+ * <ETag>"b4f7f74913aab4a5ad1e6a58fcb3b274"</ETag>
+ * <Size>1039050</Size>
+ * <StorageClass>STANDARD</StorageClass>
+ * </Contents>
+ */
+ const relevantObjs = _.filter(fileObjs, fileObj => {
+ const key = fileObj.Key._text;
+ const isInFolderOfInterest = _.includes(key, folderName);
+ const isFileEntry = !_.endsWith(key, '/');
+ return isInFolderOfInterest && isFileEntry;
+ });
+
+ const versionFilePaths = _.map(relevantObjs, fileObj => {
return fileObj.Key._text;
});
- return versionFileNames;
+ return versionFilePaths;
},
- async getJSONDocFileAsync(fileName: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> {
- const endpoint = `${s3DocJsonRoot}/${fileName}`;
+ async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> {
+ const endpoint = `${s3DocJsonRoot}/${filePath}`;
const response = await fetch(endpoint);
if (response.status !== 200) {
// TODO: Show the user an error message when the docs fail to load