From ac5f81104e439a4cca016f09259cad5804199d4f Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Sun, 8 Jul 2018 19:47:57 +0200 Subject: [PATCH 01/69] Fix #1684 and some excessive Header rerendering --- app/App.jsx | 6 ++-- app/components/Account/AccountSelector.jsx | 2 +- app/components/Layout/Header.jsx | 38 ++++++++++++++-------- app/components/Modal/SendModal.jsx | 6 ++-- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/app/App.jsx b/app/App.jsx index db833ca5da..95ef9730d3 100644 --- a/app/App.jsx +++ b/app/App.jsx @@ -116,7 +116,6 @@ const CreateWorker = Loadable({ import LoginSelector from "./components/LoginSelector"; import {CreateWalletFromBrainkey} from "./components/Wallet/WalletCreate"; -import BlockchainActions from "./actions/BlockchainActions"; class App extends React.Component { constructor() { @@ -308,8 +307,7 @@ class App extends React.Component { render() { let {incognito, incognitoWarningDismissed} = this.state; - let {walletMode, theme} = this.props; - + let {walletMode, theme, location, match, ...others} = this.props; let content = null; if (this.state.syncFail) { @@ -327,7 +325,7 @@ class App extends React.Component { } else { content = (
-
+
diff --git a/app/components/Account/AccountSelector.jsx b/app/components/Account/AccountSelector.jsx index 16c03f8222..87e7b7afec 100644 --- a/app/components/Account/AccountSelector.jsx +++ b/app/components/Account/AccountSelector.jsx @@ -38,7 +38,7 @@ class AccountSelector extends React.Component { tabIndex: PropTypes.number, // tabindex property to be passed to input tag disableActionButton: PropTypes.bool, // use it if you need to disable action button, allowUppercase: PropTypes.bool, // use it if you need to allow uppercase letters - typeahead: PropTypes.array + typeahead: PropTypes.bool }; static defaultProps = { diff --git a/app/components/Layout/Header.jsx b/app/components/Layout/Header.jsx index 15a605fe52..38c5be8f4a 100644 --- a/app/components/Layout/Header.jsx +++ b/app/components/Layout/Header.jsx @@ -27,6 +27,7 @@ import {ChainStore} from "bitsharesjs/es"; import WithdrawModal from "../Modal/WithdrawModalNew"; import {List} from "immutable"; import DropDownMenu from "./HeaderDropdown"; +import {withRouter} from "react-router-dom"; import {getLogo} from "branding"; var logo = getLogo(); @@ -44,7 +45,9 @@ class Header extends React.Component { super(); this.state = { active: props.location.pathname, - accountsListDropdownActive: false + accountsListDropdownActive: false, + dropdownActive: false, + dropdownSubmenuActive: false }; this.unlisten = null; @@ -109,7 +112,8 @@ class Header extends React.Component { this.state.dropdownSubmenuActive || nextState.accountsListDropdownActive !== this.state.accountsListDropdownActive || - nextProps.height !== this.props.height + nextProps.height !== this.props.height || + nextProps.location.pathname !== this.props.location.pathname ); } @@ -165,21 +169,27 @@ class Header extends React.Component { } _closeAccountsListDropdown() { - this.setState({ - accountsListDropdownActive: false - }); + if (this.state.accountsListDropdownActive) { + this.setState({ + accountsListDropdownActive: false + }); + } } _closeMenuDropdown() { - this.setState({ - dropdownActive: false - }); + if (this.state.dropdownActive) { + this.setState({ + dropdownActive: false + }); + } } _closeDropdownSubmenu() { - this.setState({ - dropdownSubmenuActive: false - }); + if (this.state.dropdownSubmenuActive) { + this.setState({ + dropdownSubmenuActive: false + }); + } } _closeDropdown() { @@ -241,7 +251,7 @@ class Header extends React.Component { }); } - _toggleDropdownMenu(e) { + _toggleDropdownMenu() { this.setState({ dropdownActive: !this.state.dropdownActive }); @@ -1195,7 +1205,7 @@ class Header extends React.Component { } } -export default connect(Header, { +Header = connect(Header, { listenTo() { return [ AccountStore, @@ -1231,3 +1241,5 @@ export default connect(Header, { }; } }); + +export default withRouter(Header); diff --git a/app/components/Modal/SendModal.jsx b/app/components/Modal/SendModal.jsx index c38ef1cd0d..cc4a5dd2c3 100644 --- a/app/components/Modal/SendModal.jsx +++ b/app/components/Modal/SendModal.jsx @@ -21,7 +21,6 @@ import utils from "common/utils"; import counterpart from "counterpart"; import {connect} from "alt-react"; import classnames from "classnames"; -import PropTypes from "prop-types"; import {getWalletName} from "branding"; class SendModal extends React.Component { @@ -916,10 +915,11 @@ SendModalConnectWrapper = connect(SendModalConnectWrapper, { listenTo() { return [AccountStore]; }, - getProps() { + getProps(props) { return { currentAccount: AccountStore.getState().currentAccount, - passwordAccount: AccountStore.getState().passwordAccount + passwordAccount: AccountStore.getState().passwordAccount, + tabIndex: props.tabIndex || 0 }; } }); From 5c8c567fdd2b9d4617c234a65c006f947e24ed48 Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Sun, 8 Jul 2018 20:01:56 +0200 Subject: [PATCH 02/69] Fix #1682: Missing isContact in HeaderDropdown (#1683) --- app/components/Layout/Header.jsx | 10 +--------- app/components/Layout/HeaderDropdown.jsx | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/components/Layout/Header.jsx b/app/components/Layout/Header.jsx index 38c5be8f4a..c1e0f23d17 100644 --- a/app/components/Layout/Header.jsx +++ b/app/components/Layout/Header.jsx @@ -287,14 +287,6 @@ class Header extends React.Component { } } - _onAddContact() { - AccountActions.addAccountContact(this.props.currentAccount); - } - - _onRemoveContact() { - AccountActions.removeAccountContact(this.props.currentAccount); - } - render() { let {active} = this.state; let { @@ -314,7 +306,6 @@ class Header extends React.Component { ? false : AccountStore.isMyAccount(a) || (passwordLogin && currentAccount === passwordAccount); - const isContact = this.props.contacts.has(currentAccount); const enableDepositWithdraw = !!a && Apis.instance() && @@ -1167,6 +1158,7 @@ class Header extends React.Component { passwordLogin={passwordLogin} onNavigate={this._onNavigate.bind(this)} isMyAccount={isMyAccount} + contacts={this.props.contacts} showAccountLinks={showAccountLinks} tradeUrl={tradeUrl} currentAccount={currentAccount} diff --git a/app/components/Layout/HeaderDropdown.jsx b/app/components/Layout/HeaderDropdown.jsx index b79ddb5745..4f31575744 100644 --- a/app/components/Layout/HeaderDropdown.jsx +++ b/app/components/Layout/HeaderDropdown.jsx @@ -2,6 +2,7 @@ import React from "react"; import Icon from "../Icon/Icon"; import Translate from "react-translate-component"; import cnames from "classnames"; +import AccountActions from "actions/AccountActions"; export default class DropDownMenu extends React.Component { shouldComponentUpdate(np) { @@ -13,6 +14,14 @@ export default class DropDownMenu extends React.Component { return shouldUpdate; } + _onAddContact() { + AccountActions.addAccountContact(this.props.currentAccount); + } + + _onRemoveContact() { + AccountActions.removeAccountContact(this.props.currentAccount); + } + render() { const { dropdownActive, @@ -25,8 +34,12 @@ export default class DropDownMenu extends React.Component { showAccountLinks, tradeUrl, enableDepositWithdraw, - currentAccount + currentAccount, + contacts } = this.props; + + let isContact = contacts.has(currentAccount); + return (
    Date: Mon, 9 Jul 2018 08:33:05 +0200 Subject: [PATCH 03/69] Add react-perf-devtool, update react. Use npm start-perf to use --- app/index.js | 4 ++++ package-lock.json | 40 ++++++++++++++++++++++++---------------- package.json | 6 ++++-- server.js | 4 +++- webpack.config.js | 3 ++- 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/app/index.js b/app/index.js index dbdc8d508a..019c870573 100644 --- a/app/index.js +++ b/app/index.js @@ -1,6 +1,10 @@ import React from "react"; import ReactDOM from "react-dom"; import AppInit from "./AppInit"; +if (__PERFORMANCE_DEVTOOL__) { + const {registerObserver} = require("react-perf-devtool"); + registerObserver(); +} const rootEl = document.getElementById("content"); const render = () => { diff --git a/package-lock.json b/package-lock.json index 94758d4f07..feaf9e478f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2331,6 +2331,7 @@ "requires": { "antd": "^3.6.4", "cross-env": "5.1.4", + "less-plugin-precompile-import": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", "normalize.css": "^8.0.0", "prop-types": "^15.6.1", "react": "16.2.0", @@ -2364,7 +2365,7 @@ }, "less-plugin-precompile-import": { "version": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", - "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84" + "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git" }, "react": { "version": "16.2.0", @@ -16251,9 +16252,9 @@ } }, "react": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz", - "integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", + "integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", @@ -16262,9 +16263,9 @@ }, "dependencies": { "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", "requires": { "core-js": "^1.0.0", "isomorphic-fetch": "^2.1.1", @@ -16272,7 +16273,7 @@ "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "ua-parser-js": "^0.7.18" } } } @@ -16315,9 +16316,9 @@ } }, "react-dom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz", - "integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", + "integrity": "sha512-1Gin+wghF/7gl4Cqcvr1DxFX2Osz7ugxSwl6gBqCMpdrxHjIFUS7GYxrFftZ9Ln44FHw0JxCFD9YtZsrbR5/4A==", "requires": { "fbjs": "^0.8.16", "loose-envify": "^1.1.0", @@ -16326,9 +16327,9 @@ }, "dependencies": { "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", "requires": { "core-js": "^1.0.0", "isomorphic-fetch": "^2.1.1", @@ -16336,7 +16337,7 @@ "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" + "ua-parser-js": "^0.7.18" } } } @@ -16348,6 +16349,7 @@ "classnames": "^2.2.1", "create-react-class": "^15.6.3", "exenv": "^1.2.2", + "foundation-apps": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff", "object-assign": ">=4.0.*", "pubsub-js": "^1.5.x", "tether": "^0.6.5" @@ -16355,7 +16357,7 @@ "dependencies": { "foundation-apps": { "version": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff", - "from": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff" + "from": "git+https://github.com/zurb/foundation-apps.git" }, "tether": { "version": "0.6.5", @@ -16469,6 +16471,12 @@ "create-react-class": "^15.5.x" } }, + "react-perf-devtool": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/react-perf-devtool/-/react-perf-devtool-3.0.7.tgz", + "integrity": "sha512-ssj0laPvONAHnQvjOJnq4pfiNJ/yL+DEG7auXvFuRVGtvrdFRZ6zAGeZMfxk5kFZD6J1kGHZK8OHtrQb/evAvA==", + "dev": true + }, "react-popover": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/react-popover/-/react-popover-0.5.7.tgz", diff --git a/package.json b/package.json index 05fe4930ff..afb23b2c22 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "profile-build": "cross-env NODE_ENV=production webpack --env.prod --env.profile --env.hash --env.baseUrl='' --profile --json > stats-prod.json", "profile-nougly": "cross-env NODE_ENV=production webpack --env.prod --env.profile --env.hash --env.noUgly --profile --json > stats-prod-nougly.json", "start": "cross-env NODE_ENV=development node server.js", + "start-perf": "cross-env NODE_ENV=development node server.js perf-dev", "prestart-electron": "cross-env NODE_ENV=production webpack --env.hash --env.noUgly --env.electron --env.prod && npm run prepare-electron", "start-electron": "electron build/electron/index.js", "fix-locale-files": "node ./app/assets/locales-fixup.js", @@ -162,11 +163,11 @@ "prop-types": "^15.6.1", "qrcode.react": "^0.7.1", "query-string": "^6.1.0", - "react": "^16.3.2", + "react": "^16.4.1", "react-autocomplete": "^1.7.2", "react-clipboard.js": "^1.0.1", "react-datepicker2": "git+https://github.com/bitshares/react-datepicker2.git#9d4c2c28a23c970badcf765c35c5493d5a49afde", - "react-dom": "^16.3.2", + "react-dom": "^16.4.1", "react-foundation-apps": "git+https://github.com/bitshares/react-foundation-apps.git", "react-highcharts": "^16.0", "react-interpolate-component": "^0.12.0", @@ -233,6 +234,7 @@ "prettier": "^1.10.2", "pretty-quick": "^1.4.1", "react-hot-loader": "^4.3.3", + "react-perf-devtool": "^3.0.7", "react-sticky-table": "1.2.0", "sass-loader": "^7.0.1", "script-loader": "^0.6.1", diff --git a/server.js b/server.js index 1914900167..7ef8451386 100644 --- a/server.js +++ b/server.js @@ -5,8 +5,10 @@ var devMiddleware = require("webpack-dev-middleware"); var hotMiddleware = require("webpack-hot-middleware"); var fs = require("fs"); +const perf_dev = process.argv[2] === "perf-dev"; + var ProgressPlugin = require("webpack/lib/ProgressPlugin"); -var config = require("./webpack.config.js")({prod: false}); +var config = require("./webpack.config.js")({prod: false, perf_dev}); var app = express(); var compiler = webpack(config); diff --git a/webpack.config.js b/webpack.config.js index 81b8d8a10d..7c33243956 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -88,7 +88,8 @@ module.exports = function(env) { __TESTNET__: !!env.testnet, __DEPRECATED__: !!env.deprecated, DEFAULT_SYMBOL: "BTS", - __GIT_BRANCH__: JSON.stringify(git.branch()) + __GIT_BRANCH__: JSON.stringify(git.branch()), + __PERFORMANCE_DEVTOOL__: !!env.perf_dev }), new webpack.ContextReplacementPlugin( /moment[\/\\]locale$/, From 892b6e5ebbb9e4b9401634a1b93e08bd128423cb Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Mon, 9 Jul 2018 08:34:59 +0200 Subject: [PATCH 04/69] Fix #1674: Show proposer name in proposal transaction summary (#1680) --- app/components/Account/Proposals.jsx | 2 + .../Blockchain/ProposedOperation.jsx | 57 +++++++++++++------ 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/app/components/Account/Proposals.jsx b/app/components/Account/Proposals.jsx index fb675b3884..51e668f6bb 100644 --- a/app/components/Account/Proposals.jsx +++ b/app/components/Account/Proposals.jsx @@ -85,6 +85,7 @@ class Proposals extends Component { .reduce((result, proposal, index) => { let isScam = false; const id = proposal.proposal.get("id"); + const proposer = proposal.proposal.get("proposer"); const expiration = proposal.proposal.get("expiration_time"); let text = proposal.operations .map((o, index) => { @@ -106,6 +107,7 @@ class Proposals extends Component { hideDate={true} proposal={true} id={id} + proposer={proposer} /> ); }) diff --git a/app/components/Blockchain/ProposedOperation.jsx b/app/components/Blockchain/ProposedOperation.jsx index 8ffb7302d0..79a869bb9f 100644 --- a/app/components/Blockchain/ProposedOperation.jsx +++ b/app/components/Blockchain/ProposedOperation.jsx @@ -127,7 +127,7 @@ class ProposedOperation extends React.Component { } render() { - let {op, current, block, hideExpiration} = this.props; + let {op, proposer, current, block, hideExpiration} = this.props; let line = null, column = null, color = "info"; @@ -147,23 +147,44 @@ class ProposedOperation extends React.Component { column = ( - - {memoComponent} +
    + {!!proposer ? +
    + +
    : null} +
    + + {memoComponent} +
    +
    ); From 72fd7f245bf80b6f6eb2247cca111333a10ec72b Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Mon, 9 Jul 2018 09:49:24 +0200 Subject: [PATCH 05/69] Fix #1675 - Include all gateway assets in Find Market search (#1677) * Update Find Markets tab - Include backedAssets - Min 3 char to initiate query - Wait timer to reduce queries * Include assets with only two letters * Include assets with only two letters * #1677: Fix input issue, cleanup component, add react-debounce-render for improved performance --- app/actions/AssetActions.js | 9 +- app/components/Exchange/MarketPicker.jsx | 4 +- app/components/Exchange/MyMarkets.jsx | 154 ++++++++--------------- package-lock.json | 8 ++ package.json | 1 + 5 files changed, 65 insertions(+), 111 deletions(-) diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index 2c9d63d814..b66249d20e 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -5,7 +5,7 @@ import WalletApi from "api/WalletApi"; import WalletDb from "stores/WalletDb"; import {ChainStore} from "bitsharesjs/es"; import big from "bignumber.js"; - +import {gatewayPrefixes} from "common/gateways"; let inProgress = {}; class AssetActions { @@ -414,13 +414,6 @@ class AssetActions { // Fetch next 10 assets for each gateAsset on request if (includeGateways) { - let gatewayPrefixes = [ - "BRIDGE", - "GDEX", - "RUDEX", - "OPEN", - "WIN" - ]; gatewayPrefixes.forEach(a => { this.getAssetList(a + "." + start, 10); }); diff --git a/app/components/Exchange/MarketPicker.jsx b/app/components/Exchange/MarketPicker.jsx index 5316381580..4ab04352dc 100644 --- a/app/components/Exchange/MarketPicker.jsx +++ b/app/components/Exchange/MarketPicker.jsx @@ -63,7 +63,7 @@ class MarketPickerWrapper extends React.Component { let isValidName = !ChainValidation.is_valid_symbol_error(toFind, true); /* Don't lookup invalid asset names */ - if (toFind && toFind.length >= 3 && !isValidName) return; + if (toFind && toFind.length >= 2 && !isValidName) return; this.setState({ inputValue: e.target.value.trim(), @@ -88,7 +88,7 @@ class MarketPickerWrapper extends React.Component { let quote = value.toUpperCase(); - if (quote.length >= 3) this.getAssetList(quote, 10, gatewayAssets); + this.getAssetList(quote, 10, gatewayAssets); this.setState({ lookupQuote: quote diff --git a/app/components/Exchange/MyMarkets.jsx b/app/components/Exchange/MyMarkets.jsx index b3c36e593c..c73f1275d5 100644 --- a/app/components/Exchange/MyMarkets.jsx +++ b/app/components/Exchange/MyMarkets.jsx @@ -9,8 +9,6 @@ import MarketRow from "./MarketRow"; import SettingsStore from "stores/SettingsStore"; import MarketsStore from "stores/MarketsStore"; import AssetStore from "stores/AssetStore"; -import ChainTypes from "../Utility/ChainTypes"; -import BindToChainState from "../Utility/BindToChainState"; import AssetName from "../Utility/AssetName"; import SettingsActions from "actions/SettingsActions"; import AssetActions from "actions/AssetActions"; @@ -21,8 +19,7 @@ import AssetSelector from "../Utility/AssetSelector"; import counterpart from "counterpart"; import LoadingIndicator from "../LoadingIndicator"; import {ChainValidation} from "bitsharesjs/es"; - -let lastLookup = new Date(); +import debounceRender from "react-debounce-render"; class MarketGroup extends React.Component { static defaultProps = { @@ -41,8 +38,7 @@ class MarketGroup extends React.Component { return { open: open !== undefined ? open : true, inverseSort: props.viewSettings.get("myMarketsInvert", true), - sortBy: props.viewSettings.get("myMarketsSort", "volume"), - inputValue: "" + sortBy: props.viewSettings.get("myMarketsSort", "volume") }; } @@ -94,7 +90,7 @@ class MarketGroup extends React.Component { // SettingsActions.changeBase(this.props.index, e.target.value); // } - _onToggle(e) { + _onToggle() { if (!this.props.findMarketTab) { let open = !this.state.open; this.setState({ @@ -120,8 +116,7 @@ class MarketGroup extends React.Component { base, marketStats, starredMarkets, - current, - findMarketTab + current } = this.props; let {sortBy, inverseSort, open} = this.state; @@ -312,24 +307,14 @@ class MarketGroup extends React.Component { } class MyMarkets extends React.Component { - static propTypes = { - core: ChainTypes.ChainAsset.isRequired - }; - static defaultProps = { activeTab: "my-market", - core: "1.3.0", setMinWidth: false }; constructor(props) { super(); - // let inputValue = null; // props.viewSettings.get("marketLookupInput", null); - // let symbols = inputValue ? inputValue.split(":") : [null]; - // let quote = symbols[0]; - // let base = symbols.length === 2 ? symbols[1] : null; - this.state = { inverseSort: props.viewSettings.get("myMarketsInvert", true), sortBy: props.viewSettings.get("myMarketsSort", "volume"), @@ -348,15 +333,6 @@ class MyMarkets extends React.Component { } shouldComponentUpdate(nextProps, nextState) { - /* Trigger a lookup when switching tabs to find-market */ - if ( - this.state.activeTab !== "find-market" && - nextState.activeTab === "find-market" && - !nextProps.searchAssets.size - ) { - this._lookupAssets("OPEN.", true); - } - return ( !Immutable.is(nextProps.searchAssets, this.props.searchAssets) || !Immutable.is(nextProps.markets, this.props.markets) || @@ -407,16 +383,19 @@ class MyMarkets extends React.Component { Ps.initialize(historyContainer); this._setMinWidth(); - - if (this.state.activeTab === "find-market") { - this._lookupAssets("OPEN.", true); - } } - componetWillUnmount() { + componentWillUnmount() { if (this.props.setMinWidth) { window.removeEventListener("resize", this._setMinWidth); } + clearTimeout(this.timer); + } + + componentWillReceiveProps(np) { + if (this.props.myMarketTab && !np.myMarketTab) { + if (this.refs.findSearchInput) this.refs.findSearchInput.focus(); + } } _setMinWidth() { @@ -477,36 +456,27 @@ class MyMarkets extends React.Component { this._setMinWidth(); } - _onInputName(e) { - let inputValue = e.target.value.trim().toUpperCase(); - let isValidName = !ChainValidation.is_valid_symbol_error( - inputValue, - true - ); + _onInputName(getBackedAssets, e) { + let toFind = e.target.value.trim().toUpperCase(); + let isValidName = !ChainValidation.is_valid_symbol_error(toFind, true); this.setState({ - inputValue + inputValue: toFind }); - /* Don't lookup invalid asset names */ - if (inputValue && inputValue.length >= 3 && !isValidName) { - return this.setState({ - assetNameError: true - }); - } else { - this.setState({ - assetNameError: false - }); + if (toFind && toFind.length >= 2 && !isValidName) return; + + if (this.state.inputValue !== toFind) { + this.timer && clearTimeout(this.timer); } - this._lookupAssets(inputValue); + + this.timer = setTimeout(() => { + this._lookupAssets(toFind, getBackedAssets); + }, 1500); } - _lookupAssets(value, force = false) { - // console.log("__lookupAssets", value, force); - if (!value && value !== "") { - return; - } - let now = new Date(); + _lookupAssets(value, gatewayAssets = false) { + if (!value && value !== "") return; let symbols = value.toUpperCase().split(":"); let quote = symbols[0]; @@ -521,19 +491,7 @@ class MyMarkets extends React.Component { marketLookupInput: value.toUpperCase() }); - if (this.state.lookupQuote !== quote || force) { - if (quote.length < 1 || now - lastLookup <= 250) { - return false; - } - this.getAssetList(quote, 50); - } else { - if (base && this.state.lookupBase !== base) { - if (base.length < 1 || now - lastLookup <= 250) { - return false; - } - this.getAssetList(base, 50); - } - } + this.getAssetList(quote, 50, gatewayAssets); } toggleActiveMarketTab(index) { @@ -559,7 +517,7 @@ class MyMarkets extends React.Component { } } - clearInput = e => { + clearInput = () => { this.setState({myMarketFilter: ""}); }; @@ -578,7 +536,6 @@ class MyMarkets extends React.Component { searchAssets, assetsLoading, preferredBases, - core, current, viewSettings, listHeight, @@ -586,6 +543,7 @@ class MyMarkets extends React.Component { userMarkets } = this.props; let {activeMarketTab, activeTab, lookupQuote, lookupBase} = this.state; + let otherMarkets = ; const myMarketTab = activeTab === "my-market"; @@ -604,18 +562,11 @@ class MyMarkets extends React.Component { // coreSymbol, "BTC", "CNY", "USD" ]; - /* By default, show the OPEN.X assets */ - if (!lookupQuote) lookupQuote = "OPEN."; - /* In the find-market tab, only use market tab 0 */ if (!myMarketTab) activeMarketTab = 0; searchAssets .filter(a => { - // Always keep core asset as an option - // if (preferredBases.indexOf(a.symbol) === 0) { - // return true; - // } if (lookupBase && lookupBase.length) { return a.symbol.indexOf(lookupBase) === 0; } @@ -648,10 +599,6 @@ class MyMarkets extends React.Component { ); bases = bases.filter(base => { - // Always keep core asset as an option - // if (preferredBases.indexOf(base) !== -1) { - // return true; - // } if (lookupBase && lookupBase.length > 1) { return base.indexOf(lookupBase) === 0; } else { @@ -930,13 +877,15 @@ class MyMarkets extends React.Component { type="text" value={this.state.inputValue} onChange={this._onInputName.bind( - this + this, + true )} placeholder={counterpart.translate( "exchange.search" )} maxLength="16" tabIndex={2} + ref="findSearchInput" /> {this.state.assetNameError ? (
    - {preferredBases.map((base, index) => { - if (!base) return null; - return ( -
  • - -
  • - ); - })} + {!myMarketTab && !this.state.inputValue + ? null + : preferredBases.map((base, index) => { + if (!base) return null; + return ( +
  • + +
  • + ); + })} {myMarketTab && hasOthers ? (
  • Date: Mon, 9 Jul 2018 17:36:23 +0200 Subject: [PATCH 06/69] #1643: Major performance improvements to portfolio rendering --- app/actions/MarketsActions.js | 5 +- app/components/Account/AccountOverview.jsx | 892 ++--------------- app/components/Account/AccountPage.jsx | 11 +- .../Account/AccountPortfolioList.jsx | 922 ++++++++++++++++++ app/components/Dashboard/MarketsTable.jsx | 16 +- app/components/Utility/EquivalentPrice.jsx | 6 +- .../Utility/EquivalentValueComponent.jsx | 6 +- .../Utility/MarketChangeComponent.jsx | 1 - app/components/Utility/MarketPrice.jsx | 10 - app/components/Utility/MarketStatsCheck.jsx | 23 +- app/components/Utility/TotalBalanceValue.jsx | 16 +- app/lib/common/utils.js | 17 + package-lock.json | 121 ++- 13 files changed, 1096 insertions(+), 950 deletions(-) create mode 100644 app/components/Account/AccountPortfolioList.jsx diff --git a/app/actions/MarketsActions.js b/app/actions/MarketsActions.js index 750e0ecda1..35caf98f03 100644 --- a/app/actions/MarketsActions.js +++ b/app/actions/MarketsActions.js @@ -31,7 +31,7 @@ function clearBatchTimeouts() { } const marketStatsQueue = []; // Queue array holding get_ticker promises -const marketStatsQueueLength = 10; // Number of get_ticker calls per batch +const marketStatsQueueLength = 500; // Number of get_ticker calls per batch const marketStatsQueueTimeout = 1.5; // Seconds before triggering a queue processing let marketStatsQueueActive = false; @@ -92,7 +92,7 @@ class MarketsActions { 0, marketStatsQueueLength ); - Promise.all(currentBatch.map(q => q.promise)) + return Promise.all(currentBatch.map(q => q.promise)) .then(results => { dispatch({ tickers: results, @@ -103,6 +103,7 @@ class MarketsActions { marketStatsQueue.splice(0, results.length); if (marketStatsQueue.length === 0) { marketStatsQueueActive = false; + return; } else { return processQueue(); } diff --git a/app/components/Account/AccountOverview.jsx b/app/components/Account/AccountOverview.jsx index c170a26688..7e9b4d45ee 100644 --- a/app/components/Account/AccountOverview.jsx +++ b/app/components/Account/AccountOverview.jsx @@ -1,41 +1,24 @@ import React from "react"; import Immutable from "immutable"; import Translate from "react-translate-component"; -import BalanceComponent from "../Utility/BalanceComponent"; import TotalBalanceValue from "../Utility/TotalBalanceValue"; -import SettleModal from "../Modal/SettleModal"; -import {BalanceValueComponent} from "../Utility/EquivalentValueComponent"; -import {Market24HourChangeComponent} from "../Utility/MarketChangeComponent"; import AssetName from "../Utility/AssetName"; import MarginPositions from "./MarginPositions"; import {RecentTransactions} from "./RecentTransactions"; import Proposals from "components/Account/Proposals"; import {ChainStore} from "bitsharesjs/es"; import SettingsActions from "actions/SettingsActions"; -import assetUtils from "common/asset_utils"; -import counterpart from "counterpart"; -import Icon from "../Icon/Icon"; -import {Link} from "react-router-dom"; -import EquivalentPrice from "../Utility/EquivalentPrice"; -import LinkToAssetById from "../Utility/LinkToAssetById"; import utils from "common/utils"; -import BorrowModal from "../Modal/BorrowModal"; -import DepositModal from "../Modal/DepositModal"; -import ReactTooltip from "react-tooltip"; -import SimpleDepositWithdraw from "../Dashboard/SimpleDepositWithdraw"; -import SimpleDepositBlocktradesBridge from "../Dashboard/SimpleDepositBlocktradesBridge"; + import {Tabs, Tab} from "../Utility/Tabs"; import AccountOrders from "./AccountOrders"; import cnames from "classnames"; import TranslateWithLinks from "../Utility/TranslateWithLinks"; import {checkMarginStatus} from "common/accountHelper"; import BalanceWrapper from "./BalanceWrapper"; -import SendModal from "../Modal/SendModal"; -import PulseIcon from "../Icon/PulseIcon"; -import WithdrawModal from "../Modal/WithdrawModalNew"; import AccountTreemap from "./AccountTreemap"; -import {getBackedCoin} from "common/gatewayUtils"; import AssetWrapper from "../Utility/AssetWrapper"; +import AccountPortfolioList from "./AccountPortfolioList"; class AccountOverview extends React.Component { constructor(props) { @@ -46,11 +29,7 @@ class AccountOverview extends React.Component { "portfolioSortDirection", true ), // alphabetical A -> B, numbers high to low - settleAsset: "1.3.0", shownAssets: props.viewSettings.get("shownAssets", "active"), - depositAsset: null, - withdrawAsset: null, - bridgeAsset: null, alwaysShowAssets: [ "BTS" // "USD", @@ -64,14 +43,6 @@ class AccountOverview extends React.Component { ] }; - this.qtyRefs = {}; - this.priceRefs = {}; - this.valueRefs = {}; - this.changeRefs = {}; - for (let key in this.sortFunctions) { - this.sortFunctions[key] = this.sortFunctions[key].bind(this); - } - this._handleFilterInput = this._handleFilterInput.bind(this); } @@ -82,72 +53,6 @@ class AccountOverview extends React.Component { }); } - sortFunctions = { - qty: function(a, b, force) { - if (Number(this.qtyRefs[a.key]) < Number(this.qtyRefs[b.key])) - return this.state.sortDirection || force ? -1 : 1; - - if (Number(this.qtyRefs[a.key]) > Number(this.qtyRefs[b.key])) - return this.state.sortDirection || force ? 1 : -1; - }, - alphabetic: function(a, b, force) { - if (a.key > b.key) - return this.state.sortDirection || force ? 1 : -1; - if (a.key < b.key) - return this.state.sortDirection || force ? -1 : 1; - return 0; - }, - priceValue: function(a, b) { - let aRef = this.priceRefs[a.key]; - let bRef = this.priceRefs[b.key]; - if (aRef && bRef) { - let aPrice = aRef.getFinalPrice(true); - let bPrice = bRef.getFinalPrice(true); - if (aPrice === null && bPrice !== null) return 1; - if (aPrice !== null && bPrice === null) return -1; - if (aPrice === null && bPrice === null) - return this.sortFunctions.alphabetic(a, b, true); - return this.state.sortDirection - ? aPrice - bPrice - : bPrice - aPrice; - } - }, - totalValue: function(a, b) { - let aRef = this.valueRefs[a.key]; - let bRef = this.valueRefs[b.key]; - if (aRef && bRef) { - let aValue = aRef.getValue(); - let bValue = bRef.getValue(); - if (!aValue && bValue) return 1; - if (aValue && !bValue) return -1; - if (!aValue && !bValue) - return this.sortFunctions.alphabetic(a, b, true); - return this.state.sortDirection - ? aValue - bValue - : bValue - aValue; - } - }, - changeValue: function(a, b) { - let aRef = this.changeRefs[a.key]; - let bRef = this.changeRefs[b.key]; - - if (aRef && bRef) { - let aValue = aRef.getValue(); - let bValue = bRef.getValue(); - let aChange = - parseFloat(aValue) != "NaN" ? parseFloat(aValue) : aValue; - let bChange = - parseFloat(bValue) != "NaN" ? parseFloat(bValue) : bValue; - let direction = - typeof this.state.sortDirection !== "undefined" - ? this.state.sortDirection - : true; - - return direction ? aChange - bChange : bChange - aChange; - } - } - }; - componentWillMount() { this._checkMarginStatus(); } @@ -166,19 +71,11 @@ class AccountOverview extends React.Component { componentWillReceiveProps(np) { if (np.account !== this.props.account) { this._checkMarginStatus(np); - this.priceRefs = {}; - this.valueRefs = {}; - this.changeRefs = {}; - setTimeout(this.forceUpdate.bind(this), 500); } } shouldComponentUpdate(nextProps, nextState) { return ( - !utils.are_equal_shallow( - nextProps.backedCoins, - this.props.backedCoins - ) || !utils.are_equal_shallow(nextProps.balances, this.props.balances) || nextProps.account !== this.props.account || nextProps.settings !== this.props.settings || @@ -188,648 +85,6 @@ class AccountOverview extends React.Component { ); } - _onSettleAsset(id, e) { - e.preventDefault(); - this.setState({ - settleAsset: id - }); - - this.refs.settlement_modal.show(); - } - - _hideAsset(asset, status) { - SettingsActions.hideAsset(asset, status); - } - - _showDepositModal(asset, e) { - e.preventDefault(); - this.setState({depositAsset: asset}, () => { - this.refs.deposit_modal_new.show(); - }); - } - - _showDepositWithdraw(action, asset, fiatModal, e) { - e.preventDefault(); - this.setState( - { - [action === "bridge_modal" - ? "bridgeAsset" - : action === "deposit_modal" - ? "depositAsset" - : "withdrawAsset"]: asset, - fiatModal - }, - () => { - this.refs[action].show(); - } - ); - } - - _getSeparator(render) { - return render ?  |  : null; - } - - triggerSend(asset) { - this.setState({send_asset: asset}, () => { - if (this.send_modal) this.send_modal.show(); - }); - } - - _renderBuy = (symbol, canBuy, assetName, emptyCell, balance) => { - if (symbol === "BTS" && balance <= 100000) { - // Precision of 5, 1 = 10^5 - return ( - - - - - - ); - } else { - return canBuy && this.props.isMyAccount ? ( - - - - - - ) : ( - emptyCell - ); - } - }; - - _renderBalances(balanceList, optionalAssets, visible) { - const {core_asset} = this.props; - let {settings, hiddenAssets, orders} = this.props; - let preferredUnit = settings.get("unit") || core_asset.get("symbol"); - let showAssetPercent = settings.get("showAssetPercent", false); - - const renderBorrow = (asset, account) => { - let isBitAsset = asset && asset.has("bitasset_data_id"); - let modalRef = "cp_modal_" + asset.get("id"); - return { - isBitAsset, - borrowModal: !isBitAsset ? null : ( - - ), - borrowLink: !isBitAsset ? null : ( - { - ReactTooltip.hide(); - this.refs[modalRef].show(); - }} - > - - - ) - }; - }; - - let balances = []; - const emptyCell = "-"; - balanceList.forEach(balance => { - let balanceObject = ChainStore.getObject(balance); - if (!balanceObject) return; - let asset_type = balanceObject.get("asset_type"); - let asset = ChainStore.getObject(asset_type); - if (!asset) return; - - let directMarketLink, settleLink, transferLink; - let symbol = ""; - - const assetName = asset.get("symbol"); - const notCore = asset.get("id") !== "1.3.0"; - const notCorePrefUnit = preferredUnit !== core_asset.get("symbol"); - - let {market} = assetUtils.parseDescription( - asset.getIn(["options", "description"]) - ); - symbol = asset.get("symbol"); - if (symbol.indexOf("OPEN.") !== -1 && !market) market = "USD"; - let preferredMarket = market ? market : preferredUnit; - - if (notCore && preferredMarket === symbol) - preferredMarket = core_asset.get("symbol"); - - /* Table content */ - directMarketLink = notCore ? ( - - - - ) : notCorePrefUnit ? ( - - - - ) : ( - emptyCell - ); - transferLink = ( - - - - ); - - let {isBitAsset, borrowModal, borrowLink} = renderBorrow( - asset, - this.props.account - ); - - /* Popover content */ - settleLink = ( - - - - ); - - const includeAsset = !hiddenAssets.includes(asset_type); - const hasBalance = !!balanceObject.get("balance"); - const hasOnOrder = !!orders[asset_type]; - - const backedCoin = getBackedCoin( - asset.get("symbol"), - this.props.backedCoins - ); - const canDeposit = - (backedCoin && backedCoin.depositAllowed) || - asset.get("symbol") == "BTS"; - - const canWithdraw = - backedCoin && - backedCoin.withdrawalAllowed && - (hasBalance && balanceObject.get("balance") != 0); - const canBuy = !!this.props.bridgeCoins.get(symbol); - - const assetAmount = balanceObject.get("balance"); - - this.qtyRefs[asset.get("symbol")] = utils.get_asset_amount( - assetAmount, - asset - ); - - balances.push( - - - - - - {hasBalance || hasOnOrder ? ( - - ) : null} - - - { - if (c && c.refs.bound_component) - this.priceRefs[asset.get("symbol")] = - c.refs.bound_component; - }} - fromAsset={asset.get("id")} - pulsate={{reverse: true, fill: "forwards"}} - hide_symbols - /> - - - { - if (c && c.refs.bound_component) - this.changeRefs[asset.get("symbol")] = - c.refs.bound_component; - }} - base={asset.get("id")} - quote={preferredUnit} - marketId={asset.get("symbol") + "_" + preferredUnit} - hide_symbols - /> - - - {hasBalance || hasOnOrder ? ( - { - if (c && c.refs.bound_component) - this.valueRefs[asset.get("symbol")] = - c.refs.bound_component; - }} - /> - ) : null} - - {showAssetPercent ? ( - - {hasBalance ? ( - - ) : null} - - ) : null} - {transferLink} - - {this._renderBuy( - asset.get("symbol"), - canBuy, - assetName, - emptyCell, - balanceObject.get("balance") - )} - - - {canDeposit && this.props.isMyAccount ? ( - - - - ) : ( - emptyCell - )} - - - {canWithdraw && this.props.isMyAccount ? ( - - {} - } - > - - - - ) : ( - emptyCell - )} - - {directMarketLink} - - {isBitAsset ? ( -
    - {borrowLink} - {borrowModal} -
    - ) : ( - emptyCell - )} - - - {isBitAsset ? ( -
    - {settleLink} -
    - ) : ( - emptyCell - )} - - - - - - - - ); - }); - - if (optionalAssets) { - optionalAssets - .filter(asset => { - let isAvailable = false; - this.props.backedCoins.get("OPEN", []).forEach(coin => { - if (coin && coin.symbol === asset) { - isAvailable = true; - } - }); - if (!!this.props.bridgeCoins.get(asset)) { - isAvailable = true; - } - let keep = true; - balances.forEach(a => { - if (a.key === asset) keep = false; - }); - return keep && isAvailable; - }) - .forEach(a => { - let asset = ChainStore.getAsset(a); - if (asset && this.props.isMyAccount) { - const includeAsset = !hiddenAssets.includes( - asset.get("id") - ); - - const thisAssetName = asset.get("symbol").split("."); - const canDeposit = - !!this.props.backedCoins - .get("OPEN", []) - .find( - a => a.backingCoinType === thisAssetName[1] - ) || - !!this.props.backedCoins - .get("RUDEX", []) - .find( - a => a.backingCoin === thisAssetName[1] - ) || - asset.get("symbol") == "BTS"; - - const canBuy = !!this.props.bridgeCoins.get( - asset.get("symbol") - ); - - const notCore = asset.get("id") !== "1.3.0"; - let {market} = assetUtils.parseDescription( - asset.getIn(["options", "description"]) - ); - if ( - asset.get("symbol").indexOf("OPEN.") !== -1 && - !market - ) - market = "USD"; - let preferredMarket = market - ? market - : core_asset - ? core_asset.get("symbol") - : "BTS"; - let directMarketLink = notCore ? ( - - - - ) : ( - emptyCell - ); - let { - isBitAsset, - borrowModal, - borrowLink - } = renderBorrow(asset, this.props.account); - if ( - (includeAsset && visible) || - (!includeAsset && !visible) - ) - balances.push( - - - - - {emptyCell} - - {emptyCell} - - - {emptyCell} - - - {emptyCell} - - {emptyCell} - - {canBuy && this.props.isMyAccount ? ( - - - - - - ) : ( - emptyCell - )} - - - {canDeposit && - this.props.isMyAccount ? ( - - - - ) : ( - emptyCell - )} - - {emptyCell} - - {directMarketLink} - - - {isBitAsset ? ( -
    - {borrowLink} - {borrowModal} -
    - ) : ( - emptyCell - )} - - {emptyCell} - - - - - - - ); - } - }); - } - - balances.sort(this.sortFunctions[this.state.sortKey]); - return balances; - } - _changeShownAssets(shownAssets = "active") { this.setState({ shownAssets @@ -866,6 +121,9 @@ class AccountOverview extends React.Component { return null; } + const preferredUnit = + settings.get("unit") || this.props.core_asset.get("symbol"); + let call_orders = [], collateral = {}, debt = {}; @@ -874,7 +132,6 @@ class AccountOverview extends React.Component { call_orders = account.get("call_orders").toJS(); let includedBalances, hiddenBalances; let account_balances = account.get("balances"); - let includedBalancesList = Immutable.List(), hiddenBalancesList = Immutable.List(); call_orders.forEach(callID => { @@ -951,16 +208,51 @@ class AccountOverview extends React.Component { } }); - let included = this._renderBalances( - includedBalancesList, - !this.state.filterValue ? this.state.alwaysShowAssets : null, - true + let included = ( + ); + includedBalances = included; - let hidden = this._renderBalances( - hiddenBalancesList, - !this.state.filterValue ? this.state.alwaysShowAsset : null + + let hidden = ( + ); + hiddenBalances = hidden; } @@ -1009,8 +301,6 @@ class AccountOverview extends React.Component { /> ); - const preferredUnit = - settings.get("unit") || this.props.core_asset.get("symbol"); const totalValueText = ( ); - includedBalances.push( + const includedPortfolioBalance = ( {totalValueText} @@ -1033,7 +323,7 @@ class AccountOverview extends React.Component { ); - hiddenBalances.push( + const hiddenPortfolioBalance = ( {totalValueText} @@ -1049,17 +339,6 @@ class AccountOverview extends React.Component { let showAssetPercent = settings.get("showAssetPercent", false); - // Find the current Openledger coins - // const currentDepositAsset = this.props.backedCoins.get("OPEN", []).find(c => { - // return c.symbol === this.state.depositAsset; - // }) || {}; - const currentWithdrawAsset = - this.props.backedCoins.get("OPEN", []).find(c => { - return c.symbol === this.state.withdrawAsset; - }) || {}; - const currentBridges = - this.props.bridgeCoins.get(this.state.bridgeAsset) || null; - // add unicode non-breaking space as subtext to Activity Tab to ensure that all titles are aligned // horizontally const hiddenSubText = "\u00a0"; @@ -1104,7 +383,7 @@ class AccountOverview extends React.Component { >
  • - {hiddenBalances.length ? ( + {hiddenBalancesList.size ? (
    - {/* Send Modal */} - { - if (e) this.send_modal = e; - }} - from_name={this.props.account.get("name")} - asset_id={this.state.send_asset || "1.3.0"} - /> {shownAssets != "visual" ? ( @@ -1271,11 +541,16 @@ class AccountOverview extends React.Component { + {shownAssets == "hidden" && + hiddenBalancesList.size + ? hiddenBalances + : includedBalances} + {shownAssets == "hidden" && - hiddenBalances.length - ? hiddenBalances - : includedBalances} + hiddenBalancesList.size + ? hiddenPortfolioBalance + : includedPortfolioBalance}
    ) : ( @@ -1386,57 +661,6 @@ class AccountOverview extends React.Component {
- - {/* Settle Modal */} - - - {/* Withdraw Modal*/} - - - - - {/* Deposit Modal */} - - - {/* Bridge modal */} -
); } diff --git a/app/components/Account/AccountPage.jsx b/app/components/Account/AccountPage.jsx index ca2e6895c6..2ef25bce9b 100644 --- a/app/components/Account/AccountPage.jsx +++ b/app/components/Account/AccountPage.jsx @@ -3,7 +3,6 @@ import AccountActions from "actions/AccountActions"; import AccountStore from "stores/AccountStore"; import SettingsStore from "stores/SettingsStore"; import WalletUnlockStore from "stores/WalletUnlockStore"; -import GatewayStore from "stores/GatewayStore"; // import AccountLeftPanel from "./AccountLeftPanel"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; @@ -84,9 +83,6 @@ class AccountPage extends React.Component { contained: true, balances: account.get("balances", List()).toList(), orders: account.get("orders", List()).toList(), - backedCoins: this.props.backedCoins, - bridgeCoins: this.props.bridgeCoins, - gatewayDown: this.props.gatewayDown, viewSettings: this.props.viewSettings, proxy: account.getIn(["options", "voting_account"]), history: this.props.history @@ -200,7 +196,7 @@ class AccountPageStoreWrapper extends React.Component { export default connect(AccountPageStoreWrapper, { listenTo() { - return [AccountStore, SettingsStore, WalletUnlockStore, GatewayStore]; + return [AccountStore, SettingsStore, WalletUnlockStore]; }, getProps() { return { @@ -209,10 +205,7 @@ export default connect(AccountPageStoreWrapper, { settings: SettingsStore.getState().settings, hiddenAssets: SettingsStore.getState().hiddenAssets, wallet_locked: WalletUnlockStore.getState().locked, - viewSettings: SettingsStore.getState().viewSettings, - backedCoins: GatewayStore.getState().backedCoins, - bridgeCoins: GatewayStore.getState().bridgeCoins, - gatewayDown: GatewayStore.getState().down + viewSettings: SettingsStore.getState().viewSettings }; } }); diff --git a/app/components/Account/AccountPortfolioList.jsx b/app/components/Account/AccountPortfolioList.jsx new file mode 100644 index 0000000000..ce17df0e26 --- /dev/null +++ b/app/components/Account/AccountPortfolioList.jsx @@ -0,0 +1,922 @@ +import React from "react"; +import debounceRender from "react-debounce-render"; +import BalanceComponent from "../Utility/BalanceComponent"; +import {BalanceValueComponent} from "../Utility/EquivalentValueComponent"; +import {Market24HourChangeComponent} from "../Utility/MarketChangeComponent"; +import assetUtils from "common/asset_utils"; +import counterpart from "counterpart"; +import {Link} from "react-router-dom"; +import EquivalentPrice from "../Utility/EquivalentPrice"; +import LinkToAssetById from "../Utility/LinkToAssetById"; +import BorrowModal from "../Modal/BorrowModal"; +import ReactTooltip from "react-tooltip"; +import {getBackedCoin} from "common/gatewayUtils"; +import {ChainStore} from "bitsharesjs/es"; +import {connect} from "alt-react"; +import SettingsStore from "stores/SettingsStore"; +import GatewayStore from "stores/GatewayStore"; +import MarketsStore from "stores/MarketsStore"; +import Icon from "../Icon/Icon"; +import PulseIcon from "../Icon/PulseIcon"; +import utils from "common/utils"; +import SendModal from "../Modal/SendModal"; +import SettingsActions from "actions/SettingsActions"; +import SettleModal from "../Modal/SettleModal"; +import DepositModal from "../Modal/DepositModal"; +import SimpleDepositWithdraw from "../Dashboard/SimpleDepositWithdraw"; +import SimpleDepositBlocktradesBridge from "../Dashboard/SimpleDepositBlocktradesBridge"; +import WithdrawModal from "../Modal/WithdrawModalNew"; + +class AccountPortfolioList extends React.Component { + constructor() { + super(); + + this.state = { + settleAsset: "1.3.0", + depositAsset: null, + withdrawAsset: null, + bridgeAsset: null, + allRefsAssigned: false + }; + + this.qtyRefs = {}; + this.priceRefs = {}; + this.valueRefs = {}; + this.changeRefs = {}; + for (let key in this.sortFunctions) { + this.sortFunctions[key] = this.sortFunctions[key].bind(this); + } + this._checkRefAssignments = this._checkRefAssignments.bind(this); + } + + componentWillMount() { + this.refCheckInterval = setInterval(this._checkRefAssignments); + } + + componentWillUnmount() { + clearInterval(this.refCheckInterval); + } + + _checkRefAssignments() { + /* + * In order for sorting to work all refs must be assigned, so we check + * this here and update the state to trigger a rerender + */ + if (!this.state.allRefsAssigned) { + let refKeys = ["qtyRefs", "priceRefs", "valueRefs", "changeRefs"]; + const allRefsAssigned = refKeys.reduce((a, b) => { + if (a === undefined) return !!Object.keys(this[b]).length; + return !!Object.keys(this[b]).length && a; + }, undefined); + if (allRefsAssigned) { + clearInterval(this.refCheckInterval); + this.setState({allRefsAssigned}); + } + } + } + + shouldComponentUpdate(np, ns) { + return ( + !utils.are_equal_shallow(ns, this.state) || + !utils.are_equal_shallow(np.backedCoins, this.props.backedCoins) || + !utils.are_equal_shallow(np.balances, this.props.balances) || + !utils.are_equal_shallow(np.balanceList, this.props.balanceList) || + !utils.are_equal_shallow( + np.optionalAssets, + this.props.optionalAssets + ) || + np.account !== this.props.account || + np.visible !== this.props.visible || + np.settings !== this.props.settings || + np.hiddenAssets !== this.props.hiddenAssets || + np.sortDirection !== this.props.sortDirection || + np.sortKey !== this.props.sortKey || + np.allMarketStats.reduce((a, value, key) => { + return ( + utils.check_market_stats( + value, + this.props.allMarketStats.get(key) + ) || a + ); + }, false) + ); + } + + sortFunctions = { + qty: function(a, b, force) { + if (Number(this.qtyRefs[a.key]) < Number(this.qtyRefs[b.key])) + return this.props.sortDirection || force ? -1 : 1; + + if (Number(this.qtyRefs[a.key]) > Number(this.qtyRefs[b.key])) + return this.props.sortDirection || force ? 1 : -1; + }, + alphabetic: function(a, b, force) { + if (a.key > b.key) + return this.props.sortDirection || force ? 1 : -1; + if (a.key < b.key) + return this.props.sortDirection || force ? -1 : 1; + return 0; + }, + priceValue: function(a, b) { + let aRef = this.priceRefs[a.key]; + let bRef = this.priceRefs[b.key]; + if (aRef && bRef) { + let aPrice = aRef.getFinalPrice(true); + let bPrice = bRef.getFinalPrice(true); + if (aPrice === null && bPrice !== null) return 1; + if (aPrice !== null && bPrice === null) return -1; + if (aPrice === null && bPrice === null) + return this.sortFunctions.alphabetic(a, b, true); + return this.props.sortDirection + ? aPrice - bPrice + : bPrice - aPrice; + } + }, + totalValue: function(a, b) { + let aRef = this.valueRefs[a.key]; + let bRef = this.valueRefs[b.key]; + if (aRef && bRef) { + let aValue = aRef.getValue(); + let bValue = bRef.getValue(); + if (!aValue && bValue) return 1; + if (aValue && !bValue) return -1; + if (!aValue && !bValue) + return this.sortFunctions.alphabetic(a, b, true); + return this.props.sortDirection + ? aValue - bValue + : bValue - aValue; + } + }, + changeValue: function(a, b) { + let aRef = this.changeRefs[a.key]; + let bRef = this.changeRefs[b.key]; + + if (aRef && bRef) { + let aValue = aRef.getValue(); + let bValue = bRef.getValue(); + let aChange = + parseFloat(aValue) != "NaN" ? parseFloat(aValue) : aValue; + let bChange = + parseFloat(bValue) != "NaN" ? parseFloat(bValue) : bValue; + let direction = + typeof this.props.sortDirection !== "undefined" + ? this.props.sortDirection + : true; + + return direction ? aChange - bChange : bChange - aChange; + } + } + }; + + triggerSend(asset) { + this.setState({send_asset: asset}, () => { + if (this.send_modal) this.send_modal.show(); + }); + } + + _onSettleAsset(id, e) { + e.preventDefault(); + this.setState({ + settleAsset: id + }); + + this.refs.settlement_modal.show(); + } + + _hideAsset(asset, status) { + SettingsActions.hideAsset(asset, status); + } + + _showDepositModal(asset, e) { + e.preventDefault(); + this.setState({depositAsset: asset}, () => { + this.refs.deposit_modal_new.show(); + }); + } + + _showDepositWithdraw(action, asset, fiatModal, e) { + e.preventDefault(); + this.setState( + { + [action === "bridge_modal" + ? "bridgeAsset" + : action === "deposit_modal" + ? "depositAsset" + : "withdrawAsset"]: asset, + fiatModal + }, + () => { + this.refs[action].show(); + } + ); + } + + _getSeparator(render) { + return render ?  |  : null; + } + + _renderBuy = (symbol, canBuy, assetName, emptyCell, balance) => { + if (symbol === "BTS" && balance <= 100000) { + // Precision of 5, 1 = 10^5 + return ( + + + + + + ); + } else { + return canBuy && this.props.isMyAccount ? ( + + + + + + ) : ( + emptyCell + ); + } + }; + + _renderBalances(balanceList, optionalAssets, visible) { + const { + coreSymbol, + preferredUnit, + settings, + hiddenAssets, + orders + } = this.props; + let showAssetPercent = settings.get("showAssetPercent", false); + + const renderBorrow = (asset, account) => { + let isBitAsset = asset && asset.has("bitasset_data_id"); + let modalRef = "cp_modal_" + asset.get("id"); + return { + isBitAsset, + borrowModal: !isBitAsset ? null : ( + + ), + borrowLink: !isBitAsset ? null : ( + { + ReactTooltip.hide(); + this.refs[modalRef].show(); + }} + > + + + ) + }; + }; + + let balances = []; + const emptyCell = "-"; + balanceList.forEach(balance => { + let balanceObject = ChainStore.getObject(balance); + if (!balanceObject) return; + let asset_type = balanceObject.get("asset_type"); + let asset = ChainStore.getObject(asset_type); + if (!asset) return; + + let directMarketLink, settleLink, transferLink; + let symbol = ""; + + const assetName = asset.get("symbol"); + const notCore = asset.get("id") !== "1.3.0"; + const notCorePrefUnit = preferredUnit !== coreSymbol; + + let {market} = assetUtils.parseDescription( + asset.getIn(["options", "description"]) + ); + symbol = asset.get("symbol"); + if (symbol.indexOf("OPEN.") !== -1 && !market) market = "USD"; + let preferredMarket = market ? market : preferredUnit; + + if (notCore && preferredMarket === symbol) + preferredMarket = coreSymbol; + + /* Table content */ + directMarketLink = notCore ? ( + + + + ) : notCorePrefUnit ? ( + + + + ) : ( + emptyCell + ); + transferLink = ( + + + + ); + + let {isBitAsset, borrowModal, borrowLink} = renderBorrow( + asset, + this.props.account + ); + + /* Popover content */ + settleLink = ( + + + + ); + + const includeAsset = !hiddenAssets.includes(asset_type); + const hasBalance = !!balanceObject.get("balance"); + const hasOnOrder = !!orders[asset_type]; + + const backedCoin = getBackedCoin( + asset.get("symbol"), + this.props.backedCoins + ); + const canDeposit = + (backedCoin && backedCoin.depositAllowed) || + asset.get("symbol") == "BTS"; + + const canWithdraw = + backedCoin && + backedCoin.withdrawalAllowed && + (hasBalance && balanceObject.get("balance") != 0); + + const canBuy = !!this.props.bridgeCoins.get(symbol); + const assetAmount = balanceObject.get("balance"); + + this.qtyRefs[asset.get("symbol")] = utils.get_asset_amount( + assetAmount, + asset + ); + + balances.push( + + + + + + {hasBalance || hasOnOrder ? ( + + ) : null} + + + { + if (c && c.refs.bound_component) + this.priceRefs[asset.get("symbol")] = + c.refs.bound_component; + }} + fromAsset={asset.get("id")} + pulsate={{reverse: true, fill: "forwards"}} + hide_symbols + /> + + + { + if (c && c.refs.bound_component) + this.changeRefs[asset.get("symbol")] = + c.refs.bound_component; + }} + base={asset.get("id")} + quote={preferredUnit} + marketId={asset.get("symbol") + "_" + preferredUnit} + hide_symbols + /> + + + {hasBalance || hasOnOrder ? ( + { + if (c && c.refs.bound_component) + this.valueRefs[asset.get("symbol")] = + c.refs.bound_component; + }} + /> + ) : null} + + {showAssetPercent ? ( + + {hasBalance ? ( + + ) : null} + + ) : null} + {transferLink} + + {this._renderBuy( + asset.get("symbol"), + canBuy, + assetName, + emptyCell, + balanceObject.get("balance") + )} + + + {canDeposit && this.props.isMyAccount ? ( + + + + ) : ( + emptyCell + )} + + + {canWithdraw && this.props.isMyAccount ? ( + + {} + } + > + + + + ) : ( + emptyCell + )} + + {directMarketLink} + + {isBitAsset ? ( +
+ {borrowLink} + {borrowModal} +
+ ) : ( + emptyCell + )} + + + {isBitAsset ? ( +
+ {settleLink} +
+ ) : ( + emptyCell + )} + + + + + + + + ); + }); + + if (optionalAssets) { + optionalAssets + .filter(asset => { + let isAvailable = false; + this.props.backedCoins.get("OPEN", []).forEach(coin => { + if (coin && coin.symbol === asset) { + isAvailable = true; + } + }); + if (!!this.props.bridgeCoins.get(asset)) { + isAvailable = true; + } + let keep = true; + balances.forEach(a => { + if (a.key === asset) keep = false; + }); + return keep && isAvailable; + }) + .forEach(a => { + let asset = ChainStore.getAsset(a); + if (asset && this.props.isMyAccount) { + const includeAsset = !hiddenAssets.includes( + asset.get("id") + ); + + const thisAssetName = asset.get("symbol").split("."); + const canDeposit = + !!this.props.backedCoins + .get("OPEN", []) + .find( + a => a.backingCoinType === thisAssetName[1] + ) || + !!this.props.backedCoins + .get("RUDEX", []) + .find( + a => a.backingCoin === thisAssetName[1] + ) || + asset.get("symbol") == "BTS"; + + const canBuy = !!this.props.bridgeCoins.get( + asset.get("symbol") + ); + + const notCore = asset.get("id") !== "1.3.0"; + let {market} = assetUtils.parseDescription( + asset.getIn(["options", "description"]) + ); + if ( + asset.get("symbol").indexOf("OPEN.") !== -1 && + !market + ) + market = "USD"; + let preferredMarket = market ? market : coreSymbol; + + let directMarketLink = notCore ? ( + + + + ) : ( + emptyCell + ); + let { + isBitAsset, + borrowModal, + borrowLink + } = renderBorrow(asset, this.props.account); + if ( + (includeAsset && visible) || + (!includeAsset && !visible) + ) + balances.push( + + + + + {emptyCell} + + {emptyCell} + + + {emptyCell} + + + {emptyCell} + + {emptyCell} + + {canBuy && this.props.isMyAccount ? ( + + + + + + ) : ( + emptyCell + )} + + + {canDeposit && + this.props.isMyAccount ? ( + + + + ) : ( + emptyCell + )} + + {emptyCell} + + {directMarketLink} + + + {isBitAsset ? ( +
+ {borrowLink} + {borrowModal} +
+ ) : ( + emptyCell + )} + + {emptyCell} + + + + + + + ); + } + }); + } + + balances.sort(this.sortFunctions[this.props.sortKey]); + return balances; + } + + _renderSendModal() { + return ( + { + if (e) this.send_modal = e; + }} + from_name={this.props.account.get("name")} + asset_id={this.state.send_asset || "1.3.0"} + /> + ); + } + + _renderSettleModal() { + return ( + + ); + } + + render() { + const currentWithdrawAsset = + this.props.backedCoins.get("OPEN", []).find(c => { + return c.symbol === this.state.withdrawAsset; + }) || {}; + const currentBridges = + this.props.bridgeCoins.get(this.state.bridgeAsset) || null; + + return ( + + {this._renderBalances( + this.props.balanceList, + this.props.optionalAssets, + this.props.visible + )} + {this._renderSendModal()} + {this._renderSettleModal()} + {/* Withdraw Modal*/} + + + + + {/* Deposit Modal */} + + + {/* Bridge modal */} + + + ); + } +} + +AccountPortfolioList = connect(AccountPortfolioList, { + listenTo() { + return [SettingsStore, GatewayStore, MarketsStore]; + }, + getProps() { + return { + settings: SettingsStore.getState().settings, + viewSettings: SettingsStore.getState().viewSettings, + backedCoins: GatewayStore.getState().backedCoins, + bridgeCoins: GatewayStore.getState().bridgeCoins, + gatewayDown: GatewayStore.getState().down, + allMarketStats: MarketsStore.getState().allMarketStats + }; + } +}); + +AccountPortfolioList = debounceRender(AccountPortfolioList, 50, { + leading: false +}); + +export default AccountPortfolioList; diff --git a/app/components/Dashboard/MarketsTable.jsx b/app/components/Dashboard/MarketsTable.jsx index 55949b0f41..413c81b8a7 100644 --- a/app/components/Dashboard/MarketsTable.jsx +++ b/app/components/Dashboard/MarketsTable.jsx @@ -34,23 +34,9 @@ class MarketRow extends React.Component { }; } - _checkStats(newStats = {close: {}}, oldStats = {close: {}}) { - return ( - newStats.volumeBase !== oldStats.volumeBase || - !utils.are_equal_shallow( - newStats.close && newStats.close.base, - oldStats.close && oldStats.close.base - ) || - !utils.are_equal_shallow( - newStats.close && newStats.close.quote, - oldStats.close && oldStats.close.quote - ) - ); - } - shouldComponentUpdate(np, ns) { return ( - this._checkStats(np.marketStats, this.props.marketStats) || + utils.check_market_stats(np.marketStats, this.props.marketStats) || np.base.get("id") !== this.props.base.get("id") || np.quote.get("id") !== this.props.quote.get("id") || np.visible !== this.props.visible || diff --git a/app/components/Utility/EquivalentPrice.jsx b/app/components/Utility/EquivalentPrice.jsx index c77098d988..aa51400fb8 100644 --- a/app/components/Utility/EquivalentPrice.jsx +++ b/app/components/Utility/EquivalentPrice.jsx @@ -25,12 +25,12 @@ class EquivalentPrice extends MarketStatsCheck { } getFinalPrice(real = false) { - const {coreAsset, fromAsset, toAsset, marketStats} = this.props; + const {coreAsset, fromAsset, toAsset, allMarketStats} = this.props; return MarketUtils.getFinalPrice( coreAsset, fromAsset, toAsset, - marketStats, + allMarketStats, real ); } @@ -82,7 +82,7 @@ export default class EquivalentPriceWrapper extends React.Component { ) ); }, - marketStats: () => { + allMarketStats: () => { return MarketsStore.getState().allMarketStats; } }} diff --git a/app/components/Utility/EquivalentValueComponent.jsx b/app/components/Utility/EquivalentValueComponent.jsx index e8c0159c40..6d41ff33ee 100644 --- a/app/components/Utility/EquivalentValueComponent.jsx +++ b/app/components/Utility/EquivalentValueComponent.jsx @@ -54,14 +54,14 @@ class ValueComponent extends MarketStatsCheck { toAsset, fromAsset, fullPrecision, - marketStats, + allMarketStats, coreAsset } = this.props; return MarketUtils.convertValue( amount, toAsset, fromAsset, - marketStats, + allMarketStats, coreAsset, fullPrecision ); @@ -133,7 +133,7 @@ EquivalentValueComponent = connect(EquivalentValueComponent, { }, getProps() { return { - marketStats: MarketsStore.getState().allMarketStats + allMarketStats: MarketsStore.getState().allMarketStats }; } }); diff --git a/app/components/Utility/MarketChangeComponent.jsx b/app/components/Utility/MarketChangeComponent.jsx index 5935bcc0b3..22dae756c4 100644 --- a/app/components/Utility/MarketChangeComponent.jsx +++ b/app/components/Utility/MarketChangeComponent.jsx @@ -80,7 +80,6 @@ Market24HourChangeComponent = connect(Market24HourChangeComponent, { return [MarketsStore]; }, getProps(props) { - // console.log("allMarketStats:", MarketsStore.getState().allMarketStats.toJS()); return { marketStats: MarketsStore.getState().allMarketStats.get( props.marketId diff --git a/app/components/Utility/MarketPrice.jsx b/app/components/Utility/MarketPrice.jsx index 7b1d00b126..c712ac7be7 100644 --- a/app/components/Utility/MarketPrice.jsx +++ b/app/components/Utility/MarketPrice.jsx @@ -1,7 +1,6 @@ import React from "react"; import AssetWrapper from "../Utility/AssetWrapper"; import cnames from "classnames"; -import MarketsActions from "actions/MarketsActions"; import MarketsStore from "stores/MarketsStore"; import {connect} from "alt-react"; import utils from "common/utils"; @@ -44,15 +43,6 @@ class MarketStats extends React.Component { ); } - componentWillMount() { - this.statsChecked = new Date(); - // this.statsInterval = MarketsActions.getMarketStatsInterval( - // 35 * 1000, - // this.props.base, - // this.props.quote - // ); - } - componentWillUnmount() { if (this.statsInterval) this.statsInterval(); } diff --git a/app/components/Utility/MarketStatsCheck.jsx b/app/components/Utility/MarketStatsCheck.jsx index 75f5a97985..5f552ab17a 100644 --- a/app/components/Utility/MarketStatsCheck.jsx +++ b/app/components/Utility/MarketStatsCheck.jsx @@ -6,7 +6,6 @@ import utils from "common/utils"; class MarketStatsCheck extends React.Component { constructor() { super(); - this.fromStatsIntervals = {}; this.directStatsIntervals = {}; this.toStatsInterval = null; @@ -22,14 +21,14 @@ class MarketStatsCheck extends React.Component { } _useDirectMarket(props) { - const {fromAsset, toAsset, marketStats} = props; + const {fromAsset, toAsset, allMarketStats} = props; if (!fromAsset) return false; const {marketName: directMarket} = marketUtils.getMarketName( toAsset, fromAsset ); - const directStats = marketStats.get(directMarket); + const directStats = allMarketStats.get(directMarket); if (directStats && directStats.volumeBase === 0) return false; @@ -37,7 +36,7 @@ class MarketStatsCheck extends React.Component { } _checkDirectMarkets(props) { - let {fromAssets, fromAsset, toAsset, marketStats} = props; + let {fromAssets, fromAsset, toAsset, allMarketStats} = props; if (!fromAssets && fromAsset) fromAssets = [fromAsset]; return fromAssets @@ -46,7 +45,7 @@ class MarketStatsCheck extends React.Component { return this._useDirectMarket({ fromAsset: asset, toAsset, - marketStats + allMarketStats }) ? asset.get("symbol") : null; @@ -92,7 +91,7 @@ class MarketStatsCheck extends React.Component { let useDirectMarket = this._useDirectMarket({ toAsset, fromAsset: asset, - marketStats: props.marketStats + allMarketStats: props.allMarketStats }); if (useDirectMarket && toAsset.get("id") !== asset.get("id")) { @@ -206,8 +205,8 @@ class MarketStatsCheck extends React.Component { return ( a || this._statsChanged( - np.marketStats.get(b), - this.props.marketStats.get(b) + np.allMarketStats.get(b), + this.props.allMarketStats.get(b) ) ); }, false); @@ -216,16 +215,16 @@ class MarketStatsCheck extends React.Component { return ( a || this._statsChanged( - np.marketStats.get(b), - this.props.marketStats.get(b) + np.allMarketStats.get(b), + this.props.allMarketStats.get(b) ) ); }, false); return ( this._statsChanged( - np.marketStats.get(toMarket), - this.props.marketStats.get(toMarket) + np.allMarketStats.get(toMarket), + this.props.allMarketStats.get(toMarket) ) || indirectCheck || directCheck diff --git a/app/components/Utility/TotalBalanceValue.jsx b/app/components/Utility/TotalBalanceValue.jsx index caf30ce425..a5bb5d00d4 100644 --- a/app/components/Utility/TotalBalanceValue.jsx +++ b/app/components/Utility/TotalBalanceValue.jsx @@ -62,7 +62,7 @@ class TotalValue extends MarketStatsCheck { } } - _convertValue(amount, fromAsset, toAsset, marketStats, coreAsset) { + _convertValue(amount, fromAsset, toAsset, allMarketStats, coreAsset) { if (!fromAsset || !toAsset) { return 0; } @@ -71,7 +71,7 @@ class TotalValue extends MarketStatsCheck { amount, toAsset, fromAsset, - marketStats, + allMarketStats, coreAsset ); } @@ -91,7 +91,7 @@ class TotalValue extends MarketStatsCheck { fromAssets, toAsset, balances, - marketStats, + allMarketStats, collateral, debt, openOrders, @@ -121,7 +121,7 @@ class TotalValue extends MarketStatsCheck { collateral[asset], fromAsset, toAsset, - marketStats, + allMarketStats, coreAsset ); totalValue += collateralValue; @@ -141,7 +141,7 @@ class TotalValue extends MarketStatsCheck { openOrders[asset], fromAsset, toAsset, - marketStats, + allMarketStats, coreAsset ); totalValue += orderValue; @@ -161,7 +161,7 @@ class TotalValue extends MarketStatsCheck { debt[asset], fromAsset, toAsset, - marketStats, + allMarketStats, coreAsset ); totalValue -= debtValue; @@ -183,7 +183,7 @@ class TotalValue extends MarketStatsCheck { balance.amount, fromAsset, toAsset, - marketStats, + allMarketStats, coreAsset ) : balance.amount; @@ -330,7 +330,7 @@ ValueStoreWrapper = connect(ValueStoreWrapper, { }, getProps() { return { - marketStats: MarketsStore.getState().allMarketStats, + allMarketStats: MarketsStore.getState().allMarketStats, settings: SettingsStore.getState().settings }; } diff --git a/app/lib/common/utils.js b/app/lib/common/utils.js index 93d3d0a014..9efb3e1b54 100644 --- a/app/lib/common/utils.js +++ b/app/lib/common/utils.js @@ -203,6 +203,23 @@ var Utils = { }; }, + check_market_stats: function( + newStats = {close: {}}, + oldStats = {close: {}} + ) { + let statsChanged = + newStats.volumeBase !== oldStats.volumeBase || + !this.are_equal_shallow( + newStats.close && newStats.close.base, + oldStats.close && oldStats.close.base + ) || + !this.are_equal_shallow( + newStats.close && newStats.close.quote, + oldStats.close && oldStats.close.quote + ); + return statsChanged; + }, + are_equal_shallow: function(a, b) { if ((!a && b) || (a && !b)) { return false; diff --git a/package-lock.json b/package-lock.json index 63520929ef..12d6d61c98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -593,6 +593,33 @@ "flux": "2.1.1", "is-promise": "2.1.0", "transmitter": "3.0.1" + }, + "dependencies": { + "fbjs": { + "version": "0.1.0-alpha.7", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.1.0-alpha.7.tgz", + "integrity": "sha1-rUMIuPIy+zxzYDNJ6nJdHpw5Mjw=", + "requires": { + "core-js": "^1.0.0", + "promise": "^7.0.3", + "whatwg-fetch": "^0.9.0" + } + }, + "flux": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/flux/-/flux-2.1.1.tgz", + "integrity": "sha1-LGrGUtQzdIiWhInGWG86/yajjqQ=", + "requires": { + "fbemitter": "^2.0.0", + "fbjs": "0.1.0-alpha.7", + "immutable": "^3.7.4" + } + }, + "whatwg-fetch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz", + "integrity": "sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA=" + } } }, "alt-container": { @@ -2331,7 +2358,6 @@ "requires": { "antd": "^3.6.4", "cross-env": "5.1.4", - "less-plugin-precompile-import": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", "normalize.css": "^8.0.0", "prop-types": "^15.6.1", "react": "16.2.0", @@ -2365,7 +2391,7 @@ }, "less-plugin-precompile-import": { "version": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", - "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git" + "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84" }, "react": { "version": "16.2.0", @@ -6130,39 +6156,20 @@ "integrity": "sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=", "requires": { "fbjs": "^0.8.4" - }, - "dependencies": { - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.9" - } - } } }, "fbjs": { - "version": "0.1.0-alpha.7", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.1.0-alpha.7.tgz", - "integrity": "sha1-rUMIuPIy+zxzYDNJ6nJdHpw5Mjw=", + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", "requires": { "core-js": "^1.0.0", - "promise": "^7.0.3", - "whatwg-fetch": "^0.9.0" - }, - "dependencies": { - "whatwg-fetch": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz", - "integrity": "sha1-DjaExsuZlbQ+/J3wPkw2XZX9nMA=" - } + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" } }, "fd-slicer": { @@ -6312,16 +6319,6 @@ "readable-stream": "^2.0.4" } }, - "flux": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/flux/-/flux-2.1.1.tgz", - "integrity": "sha1-LGrGUtQzdIiWhInGWG86/yajjqQ=", - "requires": { - "fbemitter": "^2.0.0", - "fbjs": "0.1.0-alpha.7", - "immutable": "^3.7.4" - } - }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -8360,7 +8357,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -8381,12 +8379,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8401,17 +8401,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -8528,7 +8531,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -8540,6 +8544,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -8554,6 +8559,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8561,12 +8567,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -8585,6 +8593,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -8665,7 +8674,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -8677,6 +8687,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -8762,7 +8773,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -8798,6 +8810,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8817,6 +8830,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -8860,12 +8874,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -16357,7 +16373,6 @@ "classnames": "^2.2.1", "create-react-class": "^15.6.3", "exenv": "^1.2.2", - "foundation-apps": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff", "object-assign": ">=4.0.*", "pubsub-js": "^1.5.x", "tether": "^0.6.5" @@ -16365,7 +16380,7 @@ "dependencies": { "foundation-apps": { "version": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff", - "from": "git+https://github.com/zurb/foundation-apps.git" + "from": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff" }, "tether": { "version": "0.6.5", From d4d67c8e42ee16aca6832cc3bf05cb9ab745a740 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Mon, 9 Jul 2018 20:50:30 +0200 Subject: [PATCH 07/69] Fix #1685: Load markets properly in MarketsTable --- app/components/Dashboard/DashboardPage.jsx | 2 +- app/components/Dashboard/MarketsTable.jsx | 138 +++++++++++---------- 2 files changed, 74 insertions(+), 66 deletions(-) diff --git a/app/components/Dashboard/DashboardPage.jsx b/app/components/Dashboard/DashboardPage.jsx index 2cf4e8224a..80ae2dc129 100644 --- a/app/components/Dashboard/DashboardPage.jsx +++ b/app/components/Dashboard/DashboardPage.jsx @@ -6,7 +6,7 @@ import LoginSelector from "../LoginSelector"; import AccountStore from "stores/AccountStore"; import {Tabs, Tab} from "../Utility/Tabs"; -import {StarredMarkets, TopMarkets, FeaturedMarkets} from "./Markets"; +import {StarredMarkets, FeaturedMarkets} from "./Markets"; class DashboardPage extends React.Component { render() { diff --git a/app/components/Dashboard/MarketsTable.jsx b/app/components/Dashboard/MarketsTable.jsx index 413c81b8a7..c51282e7db 100644 --- a/app/components/Dashboard/MarketsTable.jsx +++ b/app/components/Dashboard/MarketsTable.jsx @@ -254,6 +254,7 @@ class MarketsTable extends React.Component { } componentWillMount() { + -this.update(); ChainStore.subscribe(this.update); } @@ -344,71 +345,79 @@ class MarketsTable extends React.Component { render() { let {markets, showFlip, showHidden, filter} = this.state; - this.loaded = true; - let visibleRow = 0; - markets = markets.map(row => { - let visible = true; + const marketRows = markets + .map(row => { + let visible = true; - if (row.isHidden !== this.state.showHidden) { - visible = false; - } else if (filter) { - const quoteObject = ChainStore.getAsset(row.quote); - const baseObject = ChainStore.getAsset(row.base); + if (row.isHidden !== this.state.showHidden) { + visible = false; + } else if (filter) { + const quoteObject = ChainStore.getAsset(row.quote); + const baseObject = ChainStore.getAsset(row.base); - const {isBitAsset: quoteIsBitAsset} = utils.replaceName( - quoteObject - ); - const {isBitAsset: baseIsBitAsset} = utils.replaceName( - baseObject - ); - - let quoteSymbol = row.quote; - let baseSymbol = row.base; - - if (quoteIsBitAsset) { - quoteSymbol = "bit" + quoteSymbol; - } + const {isBitAsset: quoteIsBitAsset} = utils.replaceName( + quoteObject + ); + const {isBitAsset: baseIsBitAsset} = utils.replaceName( + baseObject + ); - if (baseIsBitAsset) { - baseSymbol = "bit" + baseSymbol; - } + let quoteSymbol = row.quote; + let baseSymbol = row.base; - const filterPair = filter.includes(":"); + if (quoteIsBitAsset) { + quoteSymbol = "bit" + quoteSymbol; + } - if (filterPair) { - const quoteFilter = filter.split(":")[0].trim(); - const baseFilter = filter.split(":")[1].trim(); + if (baseIsBitAsset) { + baseSymbol = "bit" + baseSymbol; + } - visible = - quoteSymbol - .toLowerCase() - .includes(String(quoteFilter).toLowerCase()) && - baseSymbol - .toLowerCase() - .includes(String(baseFilter).toLowerCase()); - } else { - visible = - quoteSymbol - .toLowerCase() - .includes(String(filter).toLowerCase()) || - baseSymbol - .toLowerCase() - .includes(String(filter).toLowerCase()); + const filterPair = filter.includes(":"); + + if (filterPair) { + const quoteFilter = filter.split(":")[0].trim(); + const baseFilter = filter.split(":")[1].trim(); + + visible = + quoteSymbol + .toLowerCase() + .includes(String(quoteFilter).toLowerCase()) && + baseSymbol + .toLowerCase() + .includes(String(baseFilter).toLowerCase()); + } else { + visible = + quoteSymbol + .toLowerCase() + .includes(String(filter).toLowerCase()) || + baseSymbol + .toLowerCase() + .includes(String(filter).toLowerCase()); + } } - } - - if (visible) ++visibleRow; - return ( - - ); - }); + if (!visible) return null; + + return ( + + ); + }) + .filter(r => !!r); return (
@@ -477,15 +486,14 @@ class MarketsTable extends React.Component { - - - - - - {markets} + {!marketRows.length && ( + + + + + + )} + {marketRows}
From 8d01ecc00fad4041c1f3dfdbabe96006bc642da6 Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Mon, 9 Jul 2018 20:54:26 +0200 Subject: [PATCH 08/69] Fix #1676: Asset decimal offset and table fixes (#1678) - Remove asset decimal offset on account activity - Fixes activity table visual issue --- app/components/Account/RecentTransactions.jsx | 7 ++++--- app/components/Blockchain/Operation.jsx | 7 +------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/components/Account/RecentTransactions.jsx b/app/components/Account/RecentTransactions.jsx index 42d11bb991..20bfcb6c32 100644 --- a/app/components/Account/RecentTransactions.jsx +++ b/app/components/Account/RecentTransactions.jsx @@ -300,8 +300,8 @@ class RecentTransactions extends React.Component { ]; display_history.push( - - + + {historyCount > 0 ? ( ) : null} - + +  {(this.props.showMore && historyCount > this.props.limit) || (20 && limit < historyCount) ? ( diff --git a/app/components/Blockchain/Operation.jsx b/app/components/Blockchain/Operation.jsx index 5580cb314b..665c6ff16f 100644 --- a/app/components/Blockchain/Operation.jsx +++ b/app/components/Blockchain/Operation.jsx @@ -1006,12 +1006,7 @@ class Operation extends React.Component { amount: receivedAmount, asset_id: amount.asset_id }, - arg: "amount", - decimalOffset: - op[1].receives.asset_id === - "1.3.0" - ? 3 - : null + arg: "amount" }, { type: "price", From 8e925790fb5b2ab4fd830c71db73b65dbd03f322 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Tue, 10 Jul 2018 11:44:45 +0200 Subject: [PATCH 09/69] #1575: Update bitsharesjs --- package-lock.json | 53 ++++++++++++++++------------------------------- package.json | 2 +- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 12d6d61c98..7d385995bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2358,6 +2358,7 @@ "requires": { "antd": "^3.6.4", "cross-env": "5.1.4", + "less-plugin-precompile-import": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", "normalize.css": "^8.0.0", "prop-types": "^15.6.1", "react": "16.2.0", @@ -2391,7 +2392,7 @@ }, "less-plugin-precompile-import": { "version": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", - "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84" + "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git" }, "react": { "version": "16.2.0", @@ -2443,9 +2444,9 @@ } }, "bitsharesjs": { - "version": "1.7.10", - "resolved": "https://registry.npmjs.org/bitsharesjs/-/bitsharesjs-1.7.10.tgz", - "integrity": "sha512-VFXV5PvIUF0XnP0uuHbB9U3YDeGwERvgwH56UnqzmrBXLZiMIuijjLdY2iMLhOZfQF/NbKjEUOvpBEjw0cSCmg==", + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/bitsharesjs/-/bitsharesjs-1.7.11.tgz", + "integrity": "sha512-e1mxRzxlZk6OMQ2hTE1Lga2LrQXgWptrrmMiQvcY27DeneoGhT8ObFy/6YJyLZ2Vhg9LAZnLA0eGUMuq49f50w==", "requires": { "bigi": "1.4.2", "bitsharesjs-ws": "1.5.4", @@ -8357,8 +8358,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -8379,14 +8379,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8401,20 +8399,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -8531,8 +8526,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -8544,7 +8538,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -8559,7 +8552,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8567,14 +8559,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -8593,7 +8583,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -8674,8 +8663,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -8687,7 +8675,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -8773,8 +8760,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -8810,7 +8796,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8830,7 +8815,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -8874,14 +8858,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -16373,6 +16355,7 @@ "classnames": "^2.2.1", "create-react-class": "^15.6.3", "exenv": "^1.2.2", + "foundation-apps": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff", "object-assign": ">=4.0.*", "pubsub-js": "^1.5.x", "tether": "^0.6.5" @@ -16380,7 +16363,7 @@ "dependencies": { "foundation-apps": { "version": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff", - "from": "git+https://github.com/zurb/foundation-apps.git#2b311d183325811cca371826667eacadf6b09bff" + "from": "git+https://github.com/zurb/foundation-apps.git" }, "tether": { "version": "0.6.5", diff --git a/package.json b/package.json index 84ba222f75..94e38621dc 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "alt-react": "git+https://github.com/bitshares/react.git", "bignumber.js": "^4.0.0", "bitshares-ui-style-guide": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#707f6f7e65e43c31a828ad02e3dda2adccf6cfc3", - "bitsharesjs": "^1.7.10", + "bitsharesjs": "^1.7.11", "browser-locale": "^1.0.3", "classnames": "^2.2.1", "cookies-js": "^1.2.1", From c499a2608db618a9fed308fe5484f00e3265de1d Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Tue, 10 Jul 2018 12:17:09 +0200 Subject: [PATCH 10/69] Fix #1687: Add more feedback to app init loading phase, catch sync errors --- app/AppInit.jsx | 36 +- app/assets/locales/locale-de.json | 32 +- app/assets/locales/locale-en.json | 35 +- app/assets/locales/locale-es.json | 32 +- app/assets/locales/locale-fr.json | 32 +- app/assets/locales/locale-it.json | 32 +- app/assets/locales/locale-ja.json | 32 +- app/assets/locales/locale-ko.json | 32 +- app/assets/locales/locale-ru.json | 32 +- app/assets/locales/locale-tr.json | 32 +- app/assets/locales/locale-zh.json | 32 +- .../components/_loading-indicator.scss | 372 +++++++++++------- .../stylesheets/components/_settings.scss | 1 + app/components/Settings/AccessSettings.jsx | 6 +- app/routerTransition.js | 92 +++-- package-lock.json | 6 +- package.json | 2 +- 17 files changed, 540 insertions(+), 298 deletions(-) diff --git a/app/AppInit.jsx b/app/AppInit.jsx index dacc776a02..3023aa0467 100644 --- a/app/AppInit.jsx +++ b/app/AppInit.jsx @@ -12,6 +12,7 @@ import {IntlProvider} from "react-intl"; import willTransitionTo from "./routerTransition"; import LoadingIndicator from "./components/LoadingIndicator"; import InitError from "./components/InitError"; +import SyncError from "./components/SyncError"; import counterpart from "counterpart"; /* @@ -47,23 +48,31 @@ class AppInit extends React.Component { this.state = { apiConnected: false, - apiError: false + apiError: false, + syncError: null, + status: "" }; } componentWillMount() { - willTransitionTo() + willTransitionTo(true, this._statusCallback.bind(this)) .then(() => { this.setState({ apiConnected: true, - apiError: false + apiError: false, + syncError: null }); }) .catch(err => { console.log("willTransitionTo err:", err); this.setState({ apiConnected: false, - apiError: true + apiError: true, + syncError: !err + ? null + : (err && err.message).indexOf( + "ChainStore sync error" + ) !== -1 }); }); } @@ -82,9 +91,13 @@ class AppInit extends React.Component { } } + _statusCallback(status) { + this.setState({status}); + } + render() { const {theme, apiServer} = this.props; - const {apiConnected, apiError} = this.state; + const {apiConnected, apiError, syncError, status} = this.state; if (!apiConnected) { let server = apiServer; @@ -100,11 +113,16 @@ class AppInit extends React.Component {
{!apiError ? ( + ) : syncError ? ( + ) : ( )} diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index 072ae4704c..e205ff58d7 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -417,8 +417,10 @@ "browser": "Nicht unterstützter Browser", "browser_text": "Ihr Browser ist unzureichend mit der BitShares-Wallet getestet worden. Wir empfehlen Ihnen, eine Sicherung ihrer Geldbörse durchzuführen und diese in den Chrome Browser zu importieren. Nutzen Sie Ihren Browser auf eigene Gefahr!", + "check_latency": "Running latency checks...", "connected": "verbunden", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "Nicht verbunden", "retry": "nocheinmal versuchen", "title": "Initialisierungsfehler", @@ -433,9 +435,15 @@ "coll_ratio": "Kollateral-Ratio", "errors": { "below": "Kollateral-Ratio unter Aufrechterhaltungslevel", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Your collateral ratio is close to %(mr)s which means this position is in danger of being margin called if the price drops.", - "collateral": "Unzureichendes Kollateral" + "collateral": "Unzureichendes Kollateral", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -450,6 +458,16 @@ "money_received_title": "Übertragen von %(from)s" }, "cancel": "abbrechen", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -961,10 +979,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "Konten verwalten", "account": "Konto", "account_notify": "The active account is now %(account)s", "account_value": "Kontowert", + "accounts_manage": "Konten verwalten", "collateral_ratio": "Collateral ratio", "create_account": "Konto erstellen", "create_asset": "Asset erstellen", @@ -990,7 +1008,6 @@ "update_asset": "Asset ändern" }, "icons": { - "accounts_manage": "Konten verwalten", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1054,6 +1071,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1456,6 +1474,7 @@ "passwordLogin": "Login using the account model", "password_text": "Change your password.", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "Remove", "remove_api": "Remove Node", "remove_ws": "Websocket API entfernen", @@ -1801,10 +1820,6 @@ }, "wallet": { "accept": "Zustimmen", - "account_create_wallet_text": - "This password will be used to create a new BitShares local wallet for you, which will only be stored locally in your browser. A BitShares wallet can contain multiple accounts and can be easily transferred between browsers and computers using a backup file.", - "account_exp": - "This account will be created on the blockchain and will be your address for any transfers you want to make! There are no long Bitcoin-style addresses in BitShares!", "account_public": "Account Name (Public)", "active_wallet": "Active Geldbörse", "all_set": "You're all set!", @@ -1835,8 +1850,6 @@ "brainkey_w2": "Jeder mit Zugang zu diesem Schlüssel wird", "brainkey_w3": "Zugang zu Ihren Finanzen in dieser Geldbörse erhalten", "bts_09_export": "BTS 0.9.3c key export file (.json)", - "bts_rules": - "The first rule of Bitshares is: Do not lose your password.
The second rule of Bitshares is: Do not lose your password.
The third rule of Bitshares is: We cannot recover your password.
The fourth rule: If you can remember the password, it's not secure.
The fifth rule: Use only randomly-generated passwords.
The sixth rule: Do not tell anyone your password.
The seventh rule: Always back up your password.", "cancel": "Abbrechen", "change": "Wechsele Geldbörse (%(name)s)", "change_backup": @@ -2018,7 +2031,6 @@ "
  • Multiple accounts
  • Wallet file backup required
  • High security
  • ", "wallet_move": "This backup file can also be used to move your local wallet to different computers or different browsers. In order to restore your local wallet using this backup you will also need your password!", - "wallet_new": "New BitShares account", "wallet_password": "Login anywhere using your password" }, "winex": { diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 8d5dca56f5..5167dfa7af 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -412,8 +412,10 @@ "browser": "Unsupported browser", "browser_text": "The Browser you are using has not been fully tested to support the %(wallet_name)s Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", + "check_latency": "Running latency checks...", "connected": "Connected", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "Not connected", "retry": "Retry", "title": "Application initialization issues", @@ -429,14 +431,15 @@ "errors": { "below": "Your collateral ratio is below %(mr)s which is not allowed.", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", "below_ratio_mcr_update": "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", - "increased_debt_on_margin_call": - "You increased your debt, which is not allowed when updating a margin called position", "close": "Your collateral ratio is close to %(mr)s which means this position is in danger of being margin called if the price drops.", "collateral": "Insufficient collateral balance", - "below_info": "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased." + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -451,6 +454,16 @@ "money_received_title": "Transfer from %(from)s" }, "cancel": "Cancel", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -461,16 +474,6 @@ } } }, - "connection": { - "title_out_of_sync": "Connection out of sync", - "out_of_sync": - "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", - "want_to_reconnect": - "If the connection can be recovered this message will disappear automatically.", - "automatic_reconnect": - " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", - "manual_reconnect": "Reconnect now" - }, "dashboard": { "featured_markets": "Featured Markets", "starred_markets": "Starred Markets", @@ -971,10 +974,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "Manage Accounts", "account": "Account", "account_notify": "The active account is now %(account)s", "account_value": "Account value", + "accounts_manage": "Manage Accounts", "collateral_ratio": "Collateral ratio", "create_account": "Create Account", "create_asset": "Create Asset", @@ -1002,7 +1005,6 @@ "update_asset": "Update Asset" }, "icons": { - "manage_accounts": "Manage Accounts", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1066,6 +1068,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1275,8 +1278,6 @@ "asset_reserve": "{account} burned (reserved) {amount}", "asset_settle": "{account} requested settlement of {amount}", "asset_settle_cancel": "{account} cancelled settlement of {amount}", - "asset_claim_pool": - "{account} claimed {amount} from asset {asset}'s fee pool", "asset_update": "{account} updated the asset {asset}", "asset_update_feed_producers": "{account} updated the feed producers for the asset {asset}", diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index 03da871b8b..4d652dc9fd 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -425,8 +425,10 @@ "browser": "Navegador no soportado", "browser_text": "El navegador que está utilizando no se ha probado completamente para admitir la billetera BitShares. Le recomendamos encarecidamente que haga una copia de seguridad de su monedero local e importarlo utilizando el navegador Chrome hasta que hayamos tenido más tiempo para probar completamente el navegador de su elección. Úselo bajo su propio riesgo.", + "check_latency": "Running latency checks...", "connected": "Conectado", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "No conectado", "retry": "Reintentar", "title": "Problemas de inicialización de la aplicación", @@ -441,9 +443,15 @@ "coll_ratio": "Proporción", "errors": { "below": "Su colateral está por debajo %(mr)s y no está permitido.", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Su proporciòn de colateral está por debajo %(mr)s lo que significa que esta posición está en peligro de ser llamada de margen si el precio baja.", - "collateral": "Insuficiente saldo colateral" + "collateral": "Insuficiente saldo colateral", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -458,6 +466,16 @@ "money_received_title": "Transferido de %(from)s" }, "cancel": "Cancel", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -972,10 +990,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "Cuentas de administración", "account": "Cuenta", "account_notify": "La cuenta activa es ahora %(account)s", "account_value": "Valor de la cuenta", + "accounts_manage": "Cuentas de administración", "collateral_ratio": "Collateral ratio", "create_account": "Crear Cuenta", "create_asset": "Crear Activo", @@ -1001,7 +1019,6 @@ "update_asset": "Actualizar activo" }, "icons": { - "accounts_manage": "Cuentas de administración", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1065,6 +1082,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1475,6 +1493,7 @@ "passwordLogin": "Modo de acceso", "password_text": "cambia tu contraseña.", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "retirar", "remove_api": "Eliminar nodo", "remove_ws": "Remover API websocket", @@ -1830,10 +1849,6 @@ }, "wallet": { "accept": "Aceptar", - "account_create_wallet_text": - "Esta contraseña se usará para crear una nueva billetera local de BitShares, que solo se almacenará localmente en su navegador. Un monedero BitShares puede contener múltiples cuentas y se puede transferir fácilmente entre navegadores y computadoras utilizando un archivo de respaldo.", - "account_exp": - "¡Esta cuenta se creará en blockchain y será su dirección para cualquier transferencia que quiera hacer! ¡No hay largas direcciones estilo Bitcoin en BitShares!", "account_public": "Nombre de la cuenta (Public)", "active_wallet": "Billetera Activa", "all_set": "¡Estás listo!", @@ -1863,8 +1878,6 @@ "brainkey_w2": "Cualquiera con acceso a su llave de recuperación", "brainkey_w3": "tendrá acceso a los fondos de esta billetera.", "bts_09_export": "BTS 0.9.3c Exportar el file de la llave (.json)", - "bts_rules": - "La primera regla de BitShares es: No pierdas tu contraseña.
    La segunda regla de BitShares es: No pierdas tu contraseña.
    La tercera regla de BitShares es: no podemos recuperar su contraseña.
    La cuarta regla: si puede recordar la contraseña, no es segura.
    La quinta regla: use solo contraseñas generadas aleatoriamente.
    La sexta regla: No le digas a nadie tu contraseña.
    La séptima regla: Siempre haz una copia de seguridad de tu contraseña.", "cancel": "Cancelar", "change": "Cambiar (%(name)s Billetera)", "change_backup": @@ -2047,7 +2060,6 @@ "
  • Multiples cuentas
  • Se requiere una copia de seguridad del archivo Wallet
  • Alta seguridad
  • ", "wallet_move": "Este archivo de respaldo también se puede usar para mover su billetera local a diferentes computadoras o navegadores diferentes. ¡Para restaurar su billetera local usando esta copia de seguridad , también necesitará su contraseña ", - "wallet_new": "Nueva cuenta BitShares", "wallet_password": "Inicie sesión en cualquier lugar con su contraseña" }, "winex": { diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index 316ab0beca..e05c527f67 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -412,8 +412,10 @@ "browser": "Unsupported browser", "browser_text": "The Browser you are using has not been fully tested to support the BitShares Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", + "check_latency": "Running latency checks...", "connected": "Connected", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "Not connected", "retry": "Retry", "title": "Application initialization issues", @@ -429,9 +431,15 @@ "errors": { "below": "Your collateral ratio is below %(mr)s which is not allowed.", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Your collateral ratio is close to %(mr)s which means this position is in danger of being margin called if the price drops.", - "collateral": "Insufficient collateral balance" + "collateral": "Insufficient collateral balance", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -446,6 +454,16 @@ "money_received_title": "Transfert à partir de %(from)s" }, "cancel": "Cancel", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -956,10 +974,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "Gérer les comptes", "account": "Account", "account_notify": "The active account is now %(account)s", "account_value": "Valeur de compte", + "accounts_manage": "Gérer les comptes", "collateral_ratio": "Collateral ratio", "create_account": "Créér un compte", "create_asset": "Créér un actif", @@ -987,7 +1005,6 @@ "update_asset": "Update Asset" }, "icons": { - "accounts_manage": "Gérer les comptes", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1051,6 +1068,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1453,6 +1471,7 @@ "passwordLogin": "Login using the account model", "password_text": "Change your password.", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "Remove", "remove_api": "Remove Node", "remove_ws": "Remove Node", @@ -1800,10 +1819,6 @@ }, "wallet": { "accept": "Accept", - "account_create_wallet_text": - "This password will be used to create a new BitShares local wallet for you, which will only be stored locally in your browser. A BitShares wallet can contain multiple accounts and can be easily transferred between browsers and computers using a backup file.", - "account_exp": - "This account will be created on the blockchain and will be your address for any transfers you want to make! There are no long Bitcoin-style addresses in BitShares!", "account_public": "Account Name (Public)", "active_wallet": "Active Local Wallet", "all_set": "You're all set!", @@ -1834,8 +1849,6 @@ "brainkey_w2": "Anyone with access to your recovery key will", "brainkey_w3": "have access to funds within this local wallet.", "bts_09_export": "BTS 0.9.3c key export file (.json)", - "bts_rules": - "The first rule of Bitshares is: Do not lose your password.
    The second rule of Bitshares is: Do not lose your password.
    The third rule of Bitshares is: We cannot recover your password.
    The fourth rule: If you can remember the password, it's not secure.
    The fifth rule: Use only randomly-generated passwords.
    The sixth rule: Do not tell anyone your password.
    The seventh rule: Always back up your password.", "cancel": "Cancel", "change": "Change to %(name)s", "change_backup": @@ -2017,7 +2030,6 @@ "
  • Multiple accounts
  • Wallet file backup required
  • High security
  • ", "wallet_move": "This backup file can also be used to move your local wallet to different computers or different browsers. In order to restore your local wallet using this backup you will also need your password!", - "wallet_new": "New BitShares account", "wallet_password": "Login anywhere using your password" }, "winex": { diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index 85d40aa0c2..59a0785bae 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -422,8 +422,10 @@ "browser": "Browser non supportato", "browser_text": "Il browser che stai usando non è stato pienamente testato per il supporto del portafoglio BitShares. Raccomandiamo caldamente di fare il backup del tuo portafoglio e importarlo usando il browser Chrome finché non avremo avuto il tempo di testare appieno il tuo browser. Usalo a tuo rischio.", + "check_latency": "Running latency checks...", "connected": "Connesso", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "Non connesso", "retry": "Riprova", "title": "Problemi nell'inizializzazione dell'applicazione", @@ -439,9 +441,15 @@ "errors": { "below": "Il tuo collateral ratio è inferiore a %(mr)s, che non è consentito.", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Il tuo collateral ratio è vicino a %(mr)s che significa che questa posizione rischia di essere chiamata con margine se il prezzo scende.", - "collateral": "Saldo di garanzia insufficiente" + "collateral": "Saldo di garanzia insufficiente", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -456,6 +464,16 @@ "money_received_title": "Trasferito da %(from)s" }, "cancel": "Annulla", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -972,10 +990,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "Gestisci account", "account": "Account", "account_notify": "L'account attivo è ora %(account)s", "account_value": "Valore dell'Account", + "accounts_manage": "Gestisci account", "collateral_ratio": "Collateral ratio", "create_account": "Crea Account", "create_asset": "Crea Asset", @@ -1003,7 +1021,6 @@ "update_asset": "Aggiorna Asset" }, "icons": { - "accounts_manage": "Gestisci account", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1067,6 +1084,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1473,6 +1491,7 @@ "passwordLogin": "Fai il login usando il modalità account", "password_text": "Cambia la tua password.", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "Rimuovi", "remove_api": "Rimuovi Nodo", "remove_ws": "Rimuovi Nodo", @@ -1826,10 +1845,6 @@ }, "wallet": { "accept": "Accetta", - "account_create_wallet_text": - "Questa password sarà utilizzata per creare un nuovo portafoglio BitShares, che sarà solo memorizzato localmente nel tuo browser. Un portafoglio BitShares può contenere diversi account e può essere trasferito facilmente tra browser e computer diversi usando un file di backup.", - "account_exp": - "Questo account sarà creato nella blockchain e sarà il tuo indirizzo per ogni trasferimento tu voglia effettuare! Non ci sono lunghi indirizzi stile Bitcoin su BitShares!", "account_public": "Nome account (Pubblico)", "active_wallet": "Portafoglio attivo", "all_set": "Tutto fatto!", @@ -1863,8 +1878,6 @@ "Chiunque abbia accesso alla tua chiave di recupero avrà", "brainkey_w3": "accesso ai fondi in questo portafoglio.", "bts_09_export": "File di esportazione chiavi BTS 0.9.3c (.json)", - "bts_rules": - "La prima regola di BitShares è: Non perdere la tua password.
    La seconda regola di BitShares è: Non perdere la tua password.
    La terza regola di BitShares è: Non possiamo recuperare la tua password.
    La quarta regola: Se puoi ricordare la tua password, allora non è sicura.
    La quinta regola: Usa solo password generate a caso.
    La sesta regola: Non dire a nessuno la tua password.
    La settima regola: Fai sempre il backup della tua password.", "cancel": "Annulla", "change": "Cambia a %(name)s", "change_backup": @@ -2050,7 +2063,6 @@ "
  • Account multipli
  • Necessario file di backup del portafoglio
  • Alta sicurezza
  • ", "wallet_move": "Questo file di backup può anche essere usato per spostare il tuo portafoglio su un altro computer o un altro browser. Per recuperare il tuo portafoglio usando questo backup avrai anche bisogno della password!", - "wallet_new": "Nuovo account BitShares", "wallet_password": "Fai il login dovunque usando la tua password" }, "winex": { diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index bc8c2684b5..468ba89e11 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -413,8 +413,10 @@ "browser": "サポートされていないブラウザ", "browser_text": "使用しているブラウザはBitSharesウォレットをサポートするための完全なテストが行われていません。ウォレットをバックアップし、あなたが選択したブラウザの完全なテストが行われるまで、Chromeブラウザを使用することを強く推奨します。自身の責任で使用してください。", + "check_latency": "Running latency checks...", "connected": "接続しました", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "接続していません", "retry": "再試行", "title": "アプリケーション初期化エラー", @@ -429,9 +431,15 @@ "coll_ratio": "担保比率", "errors": { "below": "あなたの担保比率は%(mr)s未満であり、許可されません。", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "あなたの担保比率は%(mr)sに近いです。そのため、価格が下落した場合、このポジションにマージンコールがかかる危険性があります。", - "collateral": "担保残高が不足しています" + "collateral": "担保残高が不足しています", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -446,6 +454,16 @@ "money_received_title": "%(from)sからの転送" }, "cancel": "キャンセル", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -958,10 +976,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "アカウントの管理", "account": "アカウント", "account_notify": "現在のアクティブアカウントは%(account)sです。", "account_value": "アカウント値", + "accounts_manage": "アカウントの管理", "collateral_ratio": "担保の比率", "create_account": "アカウント作成", "create_asset": "アセット作成", @@ -989,7 +1007,6 @@ "update_asset": "アセット更新" }, "icons": { - "accounts_manage": "アカウントの管理", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1053,6 +1070,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1450,6 +1468,7 @@ "passwordLogin": "ログインモード", "password_text": "パスワードを変更する。", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "削除", "remove_api": "ノードを削除", "remove_ws": "ノードを削除", @@ -1787,10 +1806,6 @@ }, "wallet": { "accept": "承認", - "account_create_wallet_text": - "このパスワードは新しいBitSharesウォレットの作成に使用されます。ウォレットはブラウザにのみローカルで格納されます。BitSharesウォレットには複数のアカウントを含めることができ、バックアップファイルを使用してブラウザやコンピュータ間で簡単に移動することができます。", - "account_exp": - "このアカウントはブロックチェーン上に作成され、アセット転送用のアドレスになります! BitSharesにはBitcoinスタイルの長いアドレスはありません!", "account_public": "アカウント名 (公開)", "active_wallet": "アクティブウォレット", "all_set": "準備ができました!", @@ -1822,8 +1837,6 @@ "brainkey_w2": "あなたのリカバリーキーにアクセスできる人は誰でも", "brainkey_w3": "このウォレットの資金にアクセスできます。", "bts_09_export": "BTS 0.9.3cキーエクスポートファイル (.json)", - "bts_rules": - "BitSharesの第1のルールは: パスワードをなくさないこと。
    BitSharesの第2のルールは: パスワードをなくさないでください。
    BitSharesの第3のルールは: 我々はあなたのパスワードを回復することができません。
    第4のルールは:覚えられるパスワードは安全ではありません。
    第5のルールは:ランダムに生成したパスワードのみを使用してください。
    第6のルールは:誰にもパスワードを教えないでください。
    第7のルールは:いつもパスワードをバックアップしてください。", "cancel": "キャンセル", "change": "%(name)sに変更する", "change_backup": @@ -2010,7 +2023,6 @@ "
  • 複数アカウント
  • ウォレットファイルのバックアップが必要
  • 高度なセキュリティ
  • ", "wallet_move": "このバックアップファイルによって、他のコンピュータやブラウザにウォレットを移動することができます。このバックアップを使用してウォレットをリストアするには、あなたのパスワードが必要です!", - "wallet_new": "新しいBitSharesアカウント", "wallet_password": "パスワードを使用してどこでもログイン" }, "winex": { diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index 8ac7a46680..1b78a4e604 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -412,8 +412,10 @@ "browser": "Unsupported browser", "browser_text": "The Browser you are using has not been fully tested to support the BitShares Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", + "check_latency": "Running latency checks...", "connected": "연결됨", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "연결안됨", "retry": "다시 시도", "title": "Application initialization issues", @@ -429,9 +431,15 @@ "errors": { "below": "Your collateral ratio is below %(mr)s which is not allowed.", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Your collateral ratio is close to %(mr)s which means this position is in danger of being margin called if the price drops.", - "collateral": "Insufficient collateral balance" + "collateral": "Insufficient collateral balance", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -446,6 +454,16 @@ "money_received_title": "에서 이전 %(from)s" }, "cancel": "Cancel", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -954,10 +972,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "계정 관리", "account": "계정", "account_notify": "The active account is now %(account)s", "account_value": "계정 값", + "accounts_manage": "계정 관리", "collateral_ratio": "Collateral ratio", "create_account": "계정 생성", "create_asset": "자산 생성", @@ -983,7 +1001,6 @@ "update_asset": "Update Asset" }, "icons": { - "accounts_manage": "계정 관리", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1047,6 +1064,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1448,6 +1466,7 @@ "passwordLogin": "Login using the account model", "password_text": "Change your password.", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "Remove", "remove_api": "Remove Node", "remove_ws": "웹소켓 API 제거", @@ -1782,10 +1801,6 @@ }, "wallet": { "accept": "Accept", - "account_create_wallet_text": - "This password will be used to create a new BitShares local wallet for you, which will only be stored locally in your browser. A BitShares wallet can contain multiple accounts and can be easily transferred between browsers and computers using a backup file.", - "account_exp": - "This account will be created on the blockchain and will be your address for any transfers you want to make! There are no long Bitcoin-style addresses in BitShares!", "account_public": "Account Name (Public)", "active_wallet": "현재 지갑", "all_set": "You're all set!", @@ -1815,8 +1830,6 @@ "brainkey_w2": "Anyone with access to your recovery key will", "brainkey_w3": "have access to funds within this wallet.", "bts_09_export": "BTS 0.9.3c key export file (.json)", - "bts_rules": - "The first rule of Bitshares is: Do not lose your password.
    The second rule of Bitshares is: Do not lose your password.
    The third rule of Bitshares is: We cannot recover your password.
    The fourth rule: If you can remember the password, it's not secure.
    The fifth rule: Use only randomly-generated passwords.
    The sixth rule: Do not tell anyone your password.
    The seventh rule: Always back up your password.", "cancel": "취소", "change": "(%(name)s 지갑 변경)", "change_backup": @@ -1994,7 +2007,6 @@ "
  • Multiple accounts
  • Wallet file backup required
  • High security
  • ", "wallet_move": "This backup file can also be used to move your local wallet to different computers or different browsers. In order to restore your local wallet using this backup you will also need your password!", - "wallet_new": "New BitShares account", "wallet_password": "Login anywhere using your password" }, "winex": { diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index 809824bebe..5125c2dcc4 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -426,8 +426,10 @@ "browser": "Неподдерживаемый браузер", "browser_text": "Браузер, который Вы используете, не тестировался на предмет поддержки кошелька BitShares. Мы настоятельно рекомендуем Вам сделать резервную копию вашего локального кошелька и импортировать его, используя браузер Chrome, пока мы не проведем полное тестирование выбранного Вами браузера. Мы не несем ответственности за использование Вами данного браузера.", + "check_latency": "Running latency checks...", "connected": "Соединение установлено", "connecting": "Подключение к серверу API: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "Нет соединения", "retry": "Повторить попытку", "title": "Проблемы инициализации приложения", @@ -443,9 +445,15 @@ "errors": { "below": "Ваш уровень гарантийного обеспечения ниже %(mr)s, что не допускается.", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Ваш уровень обеспечения близок к %(mr)s, что означает, что в случае падения цены, в отношении данной позиции будет совершён марджин колл.", - "collateral": "Недостаточный остаток на счете" + "collateral": "Недостаточный остаток на счете", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "Прежде чем максимизировать долг, вы должны задать коэффициент залогового обеспечения", @@ -460,6 +468,16 @@ "money_received_title": "Перевод от %(from)s" }, "cancel": "Отменить", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -976,10 +994,10 @@ "scan_qr_code": "Сканировать QR-код" }, "header": { - "accounts_manage": "Учетные записи", "account": "Аккаунт", "account_notify": "Активный аккаунт в настоящее время %(account)s", "account_value": "Оценка", + "accounts_manage": "Учетные записи", "collateral_ratio": "Коэффициент покрытия", "create_account": "Создать аккаунт", "create_asset": "Создать актив", @@ -1007,7 +1025,6 @@ "update_asset": "Обновить актив" }, "icons": { - "accounts_manage": "Учетные записи", "adjust": "Настроить маржинальную позицию", "assets": "Активы", "checkmark_circle": { @@ -1072,6 +1089,7 @@ "common": "Нажмите, чтобы разблокировать свой аккаунт", "enable_auto_scroll": "Разрешить автопрокрутку" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Отклоненные", "no": "Нет", @@ -1478,6 +1496,7 @@ "passwordLogin": "Режим входа", "password_text": "Поменяйте пароль.", "ping": "Проверить Узлы", + "pinging": "Pinging ...", "remove": "Удалить", "remove_api": "Удалить API", "remove_ws": "Удалить WebSocket API", @@ -1832,10 +1851,6 @@ }, "wallet": { "accept": "Принять", - "account_create_wallet_text": - "Этот пароль будет использован для создания Вашего нового локального кошелька BitShares, который будет храниться только в Вашем браузере. Кошелек BitShares может содержать несколько аккаунтов, а также может легко переноситься между браузерами и компьютерами с помощью резервной копии.", - "account_exp": - "Этот аккаунт будет создан в блокчейне и будет являться Вашим адресом для любых переводов, которые Вы захотите осуществить! Bitshares использует имена вместо длинных незапоминающихся адресов в стиле Биткоина!", "account_public": "Имя аккаунта (публичное)", "active_wallet": "Активный локальный кошелек", "all_set": "Всё готово!", @@ -1870,8 +1885,6 @@ "brainkey_w3": "получить доступ к средствам на этом локальном кошельке.", "bts_09_export": "Экспорт файл ключа BTS 0.9.3c (.json)", - "bts_rules": - "Первое правило BitShares: не потеряйте свой пароль.
    Второе правило BitShares: не потеряйте свой пароль.
    Третье правило BitShares: мы не можем восстановить Ваш пароль.
    Четвертое правило: если Вы помните пароль наизусть, он небезопасен.
    Пятое правило: используйте только рандомно сгенерированные пароли.
    Шестое правило: никому не говорите свой пароль.
    Седьмое правило: всегда храните копию своего пароля.", "cancel": "Отменить", "change": "Сменить на %(name)s", "change_backup": @@ -2059,7 +2072,6 @@ "
  • Несколько аккаунтов
  • Требуется резервное копирование файлов кошелька
  • Высокая безопасность
  • ", "wallet_move": "Резервная копия также может использоваться для перемещения Вашего локального кошелька на другие компьютеры или браузеры. Для восстановления локального кошелька из резервной копии Вам также понадобится Ваш пароль!", - "wallet_new": "Новый аккаунт BitShares", "wallet_password": "Войдите, используя пароль" }, "winex": { diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index 8b641aee60..78b9a8cdd7 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -418,8 +418,10 @@ "browser": "Desteklenmeyen tarayıcı", "browser_text": "Kullandığınız tarayıcı üzerinde testlerimiz devam etmektedir, bu yüzden BitShares Cüzdanını desteklemeyebilir. Cüzdanınızı yedekleyip Chrome Tarayıcısını kullanarak içeri aktarmanızı önemle tavsiye ederiz. Mesuliyet size aittir.", + "check_latency": "Running latency checks...", "connected": "Bağlandı", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "Bağlı değil", "retry": "Yeniden dene", "title": "Uygulama başlatma problemleri", @@ -435,9 +437,15 @@ "errors": { "below": "Teminat oranı çok düşük, bu pozisyon anında marjin-çağrılır", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "Your collateral ratio is close to %(mr)s which means this position is in danger of being margin called if the price drops.", - "collateral": "Yetersiz teminat seviyesi" + "collateral": "Yetersiz teminat seviyesi", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -452,6 +460,16 @@ "money_received_title": "Şuradan transfer %(from)s" }, "cancel": "İptal", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -965,10 +983,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "Hesapları yönet", "account": "Hesap", "account_notify": "Aktif hesap: %(account)s", "account_value": "Hesap değeri", + "accounts_manage": "Hesapları yönet", "collateral_ratio": "Collateral ratio", "create_account": "Hesap Oluştur", "create_asset": "Dijital Varlık Oluştur", @@ -994,7 +1012,6 @@ "update_asset": "Dijital Varlık Güncelle" }, "icons": { - "accounts_manage": "Hesapları yönet", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1058,6 +1075,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1465,6 +1483,7 @@ "passwordLogin": "Login mode", "password_text": "Şifre değiştirme", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "Remove", "remove_api": "API kaldır", "remove_ws": "Websocket API'sini kaldır", @@ -1802,10 +1821,6 @@ }, "wallet": { "accept": "Kabul", - "account_create_wallet_text": - "Bu şifre yeni bir Bitshares cüzdanı oluşturmak için kullanılacak ve tarayıcınızda saklanacaktır. Cüzdanınızı yedeklerseniz, bu şifre ile birlikte başka bilgisayarlardan ve tarayıcılardan cüzdanınıza ulaşabilirsiniz.", - "account_exp": - "This account will be created on the blockchain and will be your address for any transfers you want to make! There are no long Bitcoin-style addresses in BitShares!", "account_public": "Kullanıcı adı (herkese açık)", "active_wallet": "Etkin Cüzdan", "all_set": "İşleminiz başarıyla tamamlandı!", @@ -1835,8 +1850,6 @@ "brainkey_w2": "Kurtarma anahtarınıza ulaşan herhangi bir kimse", "brainkey_w3": "bu cüzdan içindeki fonlara ulaşabilir.", "bts_09_export": "BTS 0.9.3c yedek anahtar dosyası (.json)", - "bts_rules": - "The first rule of Bitshares is: Do not lose your password.
    The second rule of Bitshares is: Do not lose your password.
    The third rule of Bitshares is: We cannot recover your password.
    The fourth rule: If you can remember the password, it's not secure.
    The fifth rule: Use only randomly-generated passwords.
    The sixth rule: Do not tell anyone your password.
    The seventh rule: Always back up your password.", "cancel": "İptal", "change": "Değiştir (%(name)s Cüzdan)", "change_backup": @@ -2014,7 +2027,6 @@ "
  • Birden fazla sayıda hesap
  • Yedekleme dosyası zorunlu
  • Yüksek güvenlik
  • ", "wallet_move": "Cüzdan yedekleme dosyalarınızla ya da hesabınıza ait bilgilerinizle dijital varlıklarınıza başka bir bilgisayardan da erişim sağlayabilirsiniz.", - "wallet_new": "Bitshares'e Hoş Geldiniz", "wallet_password": "Şifrenizi kullanarak hesabınıza başka yerlerden erişim sağlayabilirsiniz." }, diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index 8d02a3b18d..5667fe6bf6 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -399,8 +399,10 @@ "browser": "不支持的浏览器", "browser_text": "你使用的浏览器未经过 BitShares 钱包软件的充分测试。强烈建议你备份钱包,并将其导入谷歌 Chrome 浏览器。今后经过我们充分测试后,你或许可以继续使用现在的浏览器。请了解相关风险。", + "check_latency": "Running latency checks...", "connected": "已连接", "connecting": "Connecting to API server: %(server)s", + "database": "Connection established, initializing local databases", "not_connected": "未连接", "retry": "重试", "title": "应用初始化错误", @@ -415,9 +417,15 @@ "coll_ratio": "抵押率", "errors": { "below": "抵押率低于要求的 %(mr)s,不允许操作", + "below_info": + "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "below_ratio_mcr_update": + "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", "close": "抵押率接近要求的 %(mr)s,这意味着如果价格下跌,你的债仓有可能被强制平仓。", - "collateral": "可用抵押物不足" + "collateral": "可用抵押物不足", + "increased_debt_on_margin_call": + "You increased your debt, which is not allowed when updating a margin called position" }, "maximize_debt_set_ratio_slider": "You must set a collateral ratio before being able to maximize debt", @@ -432,6 +440,16 @@ "money_received_title": "从转移 %(from)s" }, "cancel": "取消", + "connection": { + "automatic_reconnect": + " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_reconnect": "Reconnect now", + "out_of_sync": + "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", + "title_out_of_sync": "Connection out of sync", + "want_to_reconnect": + "If the connection can be recovered this message will disappear automatically." + }, "counterpart": { "formats": { "date": { @@ -928,10 +946,10 @@ "scan_qr_code": "Scan QR code" }, "header": { - "accounts_manage": "管理帐户", "account": "账户", "account_notify": "当前活跃账户为 %(account)s", "account_value": "账户价值", + "accounts_manage": "管理帐户", "collateral_ratio": "Collateral ratio", "create_account": "创建账户", "create_asset": "创建资产", @@ -957,7 +975,6 @@ "update_asset": "更新资产" }, "icons": { - "accounts_manage": "管理帐户", "adjust": "Adjust margin position", "assets": "Assets", "checkmark_circle": { @@ -1021,6 +1038,7 @@ "common": "Click to unlock your account", "enable_auto_scroll": "Enable auto scroll" }, + "manage_accounts": "Manage Accounts", "minus_circle": { "disapproved": "Disapproved", "no": "No", @@ -1409,6 +1427,7 @@ "passwordLogin": "登录方式", "password_text": "修改钱包密码。", "ping": "Ping Nodes", + "pinging": "Pinging ...", "remove": "删除", "remove_api": "移除 API 服务器节点", "remove_ws": "删除 API 服务器", @@ -1716,10 +1735,6 @@ }, "wallet": { "accept": "接受", - "account_create_wallet_text": - "这个密码将被用来创建你的钱包,并且仅保存在本地的浏览器中,而不是在云端。一个钱包中往往包含多个账户。通过传输备份文件可以轻松实现钱包的跨浏览器或跨计算机的迁移。", - "account_exp": - "此账户名将被注册在区块链中,你将可以使用此账户名进行转账等任意操作。比特股中不使用类似比特币等的长地址!", "account_public": "账户名称(公开可见)", "active_wallet": "当前使用的钱包", "all_set": "准备完成!", @@ -1749,8 +1764,6 @@ "brainkey_w2": "任何人获得了你的脑钱包密钥信息将", "brainkey_w3": "可以获得钱包中资金的使用权限。", "bts_09_export": "BTS 0.9.3c 私钥导出文件 (.json)", - "bts_rules": - "比特股法则第一条: 不要弄丢自己的密码。
    第二条法则: 不要弄丢自己的密码。
    第三条法则: 没有人能帮你恢复。
    第四条法则: 如果你仅凭脑力就能记住自己的密码,那通常来说它不够强。
    第五条法则: 只用随机生成的密码。
    第六条法则: 别告诉别人你的密码。
    第七条法则: 总是备份你的密码。", "cancel": "取消", "change": "切换到钱包 %(name)s", "change_backup": "你已经修改了密码,强烈建议你创建一个新的备份文件。", @@ -1924,7 +1937,6 @@ "
  • 多账户
  • 要求钱包文件备份
  • 安全性:高
  • ", "wallet_move": "这个备份文件也可以用来实现跨浏览器或跨计算机的钱包迁移。你将需要提供密码以进行恢复!", - "wallet_new": "新账户", "wallet_password": "从任意地点使用密码登录" }, "winex": { diff --git a/app/assets/stylesheets/components/_loading-indicator.scss b/app/assets/stylesheets/components/_loading-indicator.scss index 28f7eba407..c143a3a0e8 100644 --- a/app/assets/stylesheets/components/_loading-indicator.scss +++ b/app/assets/stylesheets/components/_loading-indicator.scss @@ -1,214 +1,310 @@ .loading-overlay { - height: 100%; - width: 100%; - position: absolute; - top: 0; left: 0; bottom: 0; right: 0; - z-index: 1 !important; - -webkit-transition: opacity linear 0.5s; - transition: opacity linear 0.5s; + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + z-index: 1 !important; + -webkit-transition: opacity linear 0.5s; + transition: opacity linear 0.5s; } .loading-overlay.ng-hide { - opacity: 0; + opacity: 0; } .loading-panel { - max-height: 110px; - width: 340px; - background-color: #999; - opacity: 0.4; - border-radius: 5px; - margin-left: auto; - margin-right: auto; - position: absolute; - top: 40%; - left: 0; - right: 0; - bottom: 0; + max-height: 110px; + width: 340px; + background-color: #999; + opacity: 0.75; + border-radius: 5px; + margin-left: auto; + margin-right: auto; + position: absolute; + top: 40%; + left: 0; + right: 0; + bottom: 0; } .splash .loading-panel { - left: -380px; + left: -380px; } .progress-indicator { - height: 50px; - vertical-align: middle; - margin: 46px 20px 20px 20px; - text-align: center; - color: #000; - display: none; + height: 50px; + vertical-align: middle; + margin: 46px 20px 20px 20px; + text-align: center; + color: #000; + display: none; } .progress-indicator > span { - vertical-align: middle; - display: table-cell; + vertical-align: middle; + display: table-cell; } .with-progress .progress-indicator { - display: table; + display: table; } .spinner { - width: 64px; - height: 18px; - margin: auto; - position: absolute; - top: 0; left: 0; bottom: 0; right: 0; + width: 64px; + height: 18px; + margin: auto; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; } .with-progress .spinner { - margin: 20px auto 0 auto; + margin: 20px auto 0 auto; } .spinner > div { - width: 18px; - height: 18px; - background-color: #333; - border-radius: 100%; - display: inline-block; - -webkit-animation: bouncedelay 1.4s infinite ease-in-out; - animation: bouncedelay 1.4s infinite ease-in-out; - /* Prevent first frame from flickering when animation starts */ - -webkit-animation-fill-mode: both; - animation-fill-mode: both; + width: 18px; + height: 18px; + background-color: #333; + border-radius: 100%; + display: inline-block; + -webkit-animation: bouncedelay 1.4s infinite ease-in-out; + animation: bouncedelay 1.4s infinite ease-in-out; + /* Prevent first frame from flickering when animation starts */ + -webkit-animation-fill-mode: both; + animation-fill-mode: both; } .spinner .bounce1 { - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; } .spinner .bounce2 { - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; } @-webkit-keyframes bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0.0) } - 40% { -webkit-transform: scale(1.0) } + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + } + 40% { + -webkit-transform: scale(1); + } } @keyframes bouncedelay { - 0%, 80%, 100% { - transform: scale(0.0); - -webkit-transform: scale(0.0); - } - 40% { - transform: scale(1.0); - -webkit-transform: scale(1.0); - } + 0%, + 80%, + 100% { + transform: scale(0); + -webkit-transform: scale(0); + } + 40% { + transform: scale(1); + -webkit-transform: scale(1); + } } // circle .circle-wrapper { - width: 22px; - height: 22px; - position: relative; + width: 22px; + height: 22px; + position: relative; } .circle { - width: 100%; - height: 100%; - position: absolute; - left: 0; - top: 0; + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; } .circle:before { - content: ''; - display: block; - margin: 0 auto; - width: 20%; - height: 20%; - background-color: #777; - - border-radius: 100%; - -webkit-animation: bouncedelay 1.2s infinite ease-in-out; - animation: bouncedelay 1.2s infinite ease-in-out; - /* Prevent first frame from flickering when animation starts */ - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.circle2 { -webkit-transform: rotate(30deg); transform: rotate(30deg) } -.circle3 { -webkit-transform: rotate(60deg); transform: rotate(60deg) } -.circle4 { -webkit-transform: rotate(90deg); transform: rotate(90deg) } -.circle5 { -webkit-transform: rotate(120deg); transform: rotate(120deg) } -.circle6 { -webkit-transform: rotate(150deg); transform: rotate(150deg) } -.circle7 { -webkit-transform: rotate(180deg); transform: rotate(180deg) } -.circle8 { -webkit-transform: rotate(210deg); transform: rotate(210deg) } -.circle9 { -webkit-transform: rotate(240deg); transform: rotate(240deg) } -.circle10 { -webkit-transform: rotate(270deg); transform: rotate(270deg) } -.circle11 { -webkit-transform: rotate(300deg); transform: rotate(300deg) } -.circle12 { -webkit-transform: rotate(330deg); transform: rotate(330deg) } - -.circle2:before { -webkit-animation-delay: -1.1s; animation-delay: -1.1s } -.circle3:before { -webkit-animation-delay: -1.0s; animation-delay: -1.0s } -.circle4:before { -webkit-animation-delay: -0.9s; animation-delay: -0.9s } -.circle5:before { -webkit-animation-delay: -0.8s; animation-delay: -0.8s } -.circle6:before { -webkit-animation-delay: -0.7s; animation-delay: -0.7s } -.circle7:before { -webkit-animation-delay: -0.6s; animation-delay: -0.6s } -.circle8:before { -webkit-animation-delay: -0.5s; animation-delay: -0.5s } -.circle9:before { -webkit-animation-delay: -0.4s; animation-delay: -0.4s } -.circle10:before { -webkit-animation-delay: -0.3s; animation-delay: -0.3s } -.circle11:before { -webkit-animation-delay: -0.2s; animation-delay: -0.2s } -.circle12:before { -webkit-animation-delay: -0.1s; animation-delay: -0.1s } + content: ""; + display: block; + margin: 0 auto; + width: 20%; + height: 20%; + background-color: #777; + + border-radius: 100%; + -webkit-animation: bouncedelay 1.2s infinite ease-in-out; + animation: bouncedelay 1.2s infinite ease-in-out; + /* Prevent first frame from flickering when animation starts */ + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +.circle2 { + -webkit-transform: rotate(30deg); + transform: rotate(30deg); +} +.circle3 { + -webkit-transform: rotate(60deg); + transform: rotate(60deg); +} +.circle4 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} +.circle5 { + -webkit-transform: rotate(120deg); + transform: rotate(120deg); +} +.circle6 { + -webkit-transform: rotate(150deg); + transform: rotate(150deg); +} +.circle7 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} +.circle8 { + -webkit-transform: rotate(210deg); + transform: rotate(210deg); +} +.circle9 { + -webkit-transform: rotate(240deg); + transform: rotate(240deg); +} +.circle10 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); +} +.circle11 { + -webkit-transform: rotate(300deg); + transform: rotate(300deg); +} +.circle12 { + -webkit-transform: rotate(330deg); + transform: rotate(330deg); +} + +.circle2:before { + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; +} +.circle3:before { + -webkit-animation-delay: -1s; + animation-delay: -1s; +} +.circle4:before { + -webkit-animation-delay: -0.9s; + animation-delay: -0.9s; +} +.circle5:before { + -webkit-animation-delay: -0.8s; + animation-delay: -0.8s; +} +.circle6:before { + -webkit-animation-delay: -0.7s; + animation-delay: -0.7s; +} +.circle7:before { + -webkit-animation-delay: -0.6s; + animation-delay: -0.6s; +} +.circle8:before { + -webkit-animation-delay: -0.5s; + animation-delay: -0.5s; +} +.circle9:before { + -webkit-animation-delay: -0.4s; + animation-delay: -0.4s; +} +.circle10:before { + -webkit-animation-delay: -0.3s; + animation-delay: -0.3s; +} +.circle11:before { + -webkit-animation-delay: -0.2s; + animation-delay: -0.2s; +} +.circle12:before { + -webkit-animation-delay: -0.1s; + animation-delay: -0.1s; +} @-webkit-keyframes bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0.0) } - 40% { -webkit-transform: scale(1.0) } + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + } + 40% { + -webkit-transform: scale(1); + } } @keyframes bouncedelay { - 0%, 80%, 100% { - -webkit-transform: scale(0.0); - transform: scale(0.0); - } 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + transform: scale(0); + } + 40% { + -webkit-transform: scale(1); + transform: scale(1); } } // three bounce .three-bounce > div { - width: 18px; - height: 18px; - background-color: #777; + width: 18px; + height: 18px; + background-color: #777; - border-radius: 100%; - display: inline-block; - -webkit-animation: bouncedelay 1.4s infinite ease-in-out; - animation: bouncedelay 1.4s infinite ease-in-out; - /* Prevent first frame from flickering when animation starts */ - -webkit-animation-fill-mode: both; - animation-fill-mode: both; + border-radius: 100%; + display: inline-block; + -webkit-animation: bouncedelay 1.4s infinite ease-in-out; + animation: bouncedelay 1.4s infinite ease-in-out; + /* Prevent first frame from flickering when animation starts */ + -webkit-animation-fill-mode: both; + animation-fill-mode: both; } .three-bounce .bounce1 { - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; } .three-bounce .bounce2 { - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; } @-webkit-keyframes bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0.0) } - 40% { -webkit-transform: scale(1.0) } + 0%, + 80%, + 100% { + -webkit-transform: scale(0); + } + 40% { + -webkit-transform: scale(1); + } } @keyframes bouncedelay { - 0%, 80%, 100% { - transform: scale(0.0); - -webkit-transform: scale(0.0); - } 40% { - transform: scale(1.0); - -webkit-transform: scale(1.0); + 0%, + 80%, + 100% { + transform: scale(0); + -webkit-transform: scale(0); + } + 40% { + transform: scale(1); + -webkit-transform: scale(1); } } - - diff --git a/app/assets/stylesheets/components/_settings.scss b/app/assets/stylesheets/components/_settings.scss index 7336388b2a..a39dd3b32f 100644 --- a/app/assets/stylesheets/components/_settings.scss +++ b/app/assets/stylesheets/components/_settings.scss @@ -94,6 +94,7 @@ div.api-status a:hover .hover-icon { } .active-node { + position: relative; margin-bottom: 2em; } diff --git a/app/components/Settings/AccessSettings.jsx b/app/components/Settings/AccessSettings.jsx index b7e3ba83b7..292f1e601b 100644 --- a/app/components/Settings/AccessSettings.jsx +++ b/app/components/Settings/AccessSettings.jsx @@ -4,8 +4,6 @@ import SettingsActions from "actions/SettingsActions"; import SettingsStore from "stores/SettingsStore"; import {settingsAPIs} from "../../api/apiConfig"; import willTransitionTo, {routerTransitioner} from "../../routerTransition"; -// import {routerTransitioner} from "../../routerTransition"; -import {withRouter} from "react-router-dom"; import {connect} from "alt-react"; import cnames from "classnames"; import Icon from "../Icon/Icon"; @@ -318,8 +316,6 @@ ApiNode.defaultProps = { hidden: false }; -const ApiNodeWithRouter = withRouter(ApiNode); - class AccessSettings extends React.Component { constructor(props) { super(props); @@ -386,7 +382,7 @@ class AccessSettings extends React.Component { !automatic && !this.isDefaultNode[node.url] ? true : false; return ( - {}) { if (this.isTransitionInProgress()) return; + this.statusCallback = statusCallback; this._willTransitionToInProgress = true; return new Promise((resolve, reject) => { @@ -109,6 +110,9 @@ class RouterTransitioner { this._willTransitionToInProgress = counterpart.translate( "settings.ping" ); + this.statusCallback( + counterpart.translate("app_init.check_latency") + ); this.doLatencyUpdate(true) .then( this._initiateConnection.bind( @@ -165,8 +169,6 @@ class RouterTransitioner { SettingsActions.updateLatencies({}); } - console.log(range); - function local_ping(thiz, range = null) { if (current < urls.length) { thiz._connectionManager.url = urls[current]; @@ -230,7 +232,16 @@ class RouterTransitioner { closeCb: this._onConnectionClose.bind(this), optionalApis: {enableOrders: true}, urlChangeCallback: url => { - console.log("fallback to new url:", url); + console.log( + "fallback to new url:", + url, + "old", + this._willTransitionToInProgress + ); + /* Update connection status */ + this.statusCallback( + counterpart.translate("app_init.connecting", {server: url}) + ); this._willTransitionToInProgress = url; SettingsActions.changeSetting({ setting: "activeNode", @@ -442,6 +453,11 @@ class RouterTransitioner { if (appInit) { // only true if app is initialized + this.statusCallback( + counterpart.translate("app_init.connecting", { + server: this._connectionManager.url + }) + ); this._connectionManager .connectWithFallback(true) .then(() => { @@ -493,7 +509,7 @@ class RouterTransitioner { this._oldChain = "old"; notify.addNotification({ message: counterpart.translate("settings.connection_error", { - url: failingNodeUrl, + url: failingNodeUrl || "", error: err }), level: "error", @@ -534,6 +550,7 @@ class RouterTransitioner { console.error("MULTIPLE CONNECT IN PROGRESS"); return; } + this.statusCallback(counterpart.translate("app_init.database")); this._connectInProgress = true; if (Apis.instance()) { if (!Apis.instance().orders_api()) @@ -580,39 +597,44 @@ class RouterTransitioner { let chainStoreResetPromise = chainChanged ? ChainStore.resetCache(false) : Promise.resolve(); - return chainStoreResetPromise.then(() => { - return Promise.all([ - PrivateKeyActions.loadDbData().then(() => { - return AccountRefsStore.loadDbData(); - }), - WalletDb.loadDbData() - .then(() => { - if (chainChanged) { - AccountStore.reset(); - return AccountStore.loadDbData( - currentChain - ).catch(err => { - console.error(err); - }); - } - }) - .catch(error => { - console.error( - "----- WalletDb.willTransitionTo error ----->", - error - ); - this._transitionDone(reject); + return chainStoreResetPromise + .then(() => { + return Promise.all([ + PrivateKeyActions.loadDbData().then(() => { + return AccountRefsStore.loadDbData(); }), - WalletManagerStore.init() - ]).then(() => { - this._connectInProgress = false; - SettingsActions.changeSetting({ - setting: "activeNode", - value: this._connectionManager.url + WalletDb.loadDbData() + .then(() => { + if (chainChanged) { + AccountStore.reset(); + return AccountStore.loadDbData( + currentChain + ).catch(err => { + console.error(err); + }); + } + }) + .catch(error => { + console.error( + "----- WalletDb.willTransitionTo error ----->", + error + ); + this._transitionDone(reject); + }), + WalletManagerStore.init() + ]).then(() => { + this._connectInProgress = false; + SettingsActions.changeSetting({ + setting: "activeNode", + value: this._connectionManager.url + }); + this._transitionDone(resolve); }); - this._transitionDone(resolve); + }) + .catch(err => { + this._connectInProgress = false; + this._transitionDone(reject.bind(this, err)); }); - }); }) .catch(err => { console.error(err); diff --git a/package-lock.json b/package-lock.json index 7d385995bd..46985e8832 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2444,9 +2444,9 @@ } }, "bitsharesjs": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/bitsharesjs/-/bitsharesjs-1.7.11.tgz", - "integrity": "sha512-e1mxRzxlZk6OMQ2hTE1Lga2LrQXgWptrrmMiQvcY27DeneoGhT8ObFy/6YJyLZ2Vhg9LAZnLA0eGUMuq49f50w==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/bitsharesjs/-/bitsharesjs-1.8.0.tgz", + "integrity": "sha512-V4EdA+LqEzH2TrB6/rZN6WWOw6N9tuaL61EDcJ2zA1XoANsCLKaEMb5pEiT0XehRVF7SHu0oJ8/xHHZ0GbcIRw==", "requires": { "bigi": "1.4.2", "bitsharesjs-ws": "1.5.4", diff --git a/package.json b/package.json index 94e38621dc..c0ad0bfd72 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "alt-react": "git+https://github.com/bitshares/react.git", "bignumber.js": "^4.0.0", "bitshares-ui-style-guide": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#707f6f7e65e43c31a828ad02e3dda2adccf6cfc3", - "bitsharesjs": "^1.7.11", + "bitsharesjs": "^1.8.0", "browser-locale": "^1.0.3", "classnames": "^2.2.1", "cookies-js": "^1.2.1", From 13c44c1c0f61f4fd14c22d318be7281c64f198e2 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Tue, 10 Jul 2018 12:32:00 +0200 Subject: [PATCH 11/69] Fix #1681: Update bitshares-ui-style-guide --- package-lock.json | 44 ++++++++------------------------------------ package.json | 2 +- 2 files changed, 9 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index 46985e8832..cf7486a3ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -712,9 +712,9 @@ "dev": true }, "antd": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/antd/-/antd-3.6.5.tgz", - "integrity": "sha512-3j9mO5g0+SnEolWEVtpo1ng84g4I961C10SZhYE3YU3c/rxl5viqA7J1LhBUM8mLMI0144i/3i+a3Q1nKS28Hg==", + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/antd/-/antd-3.6.6.tgz", + "integrity": "sha512-uQJ0REMCnmKfp9PJIYnyvgJx3TLy8U2xSYBJT7CefpevwNgKvkzmdm+Xagxtknp9cUplWbBHW0+g+Icoo93ETA==", "requires": { "array-tree-filter": "^2.0.0", "babel-runtime": "6.x", @@ -2353,8 +2353,8 @@ "dev": true }, "bitshares-ui-style-guide": { - "version": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#707f6f7e65e43c31a828ad02e3dda2adccf6cfc3", - "from": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#707f6f7e65e43c31a828ad02e3dda2adccf6cfc3", + "version": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#02a57452198f9c9b7218f38868045df599b005a5", + "from": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#02a57452198f9c9b7218f38868045df599b005a5", "requires": { "antd": "^3.6.4", "cross-env": "5.1.4", @@ -2376,20 +2376,6 @@ "is-windows": "^1.0.0" } }, - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, "less-plugin-precompile-import": { "version": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git#166550452515c03c0d497cae97bf58ba15ca1f84", "from": "git+https://github.com/gibbsfromncis/less-plugin-precompile-import.git" @@ -4710,20 +4696,6 @@ "object-assign": "^4.1.0" }, "dependencies": { - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, "immutable": { "version": "3.7.6", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", @@ -15934,9 +15906,9 @@ } }, "rc-pagination": { - "version": "1.16.4", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.16.4.tgz", - "integrity": "sha512-ZxwO3g/Wk49aaXW/pqWx9Nxw0SxQHRYeV0TAfbIVugTkd/0ZMj+GNTvWGmDMmLvA5AD0M3z9sIRtfyiGXEPWxg==", + "version": "1.16.5", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.16.5.tgz", + "integrity": "sha512-h8xUK5JeFMBH23wVOZ2HuqUPM+jss37yemxDlDCjhKeur5Ne2z6Q8L8gz+pKoE5Qz7kqLi7Vp7U2aogrwK9WtA==", "requires": { "babel-runtime": "6.x", "prop-types": "^15.5.7" diff --git a/package.json b/package.json index c0ad0bfd72..6ff2b87147 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "alt-container": "^1.0.0", "alt-react": "git+https://github.com/bitshares/react.git", "bignumber.js": "^4.0.0", - "bitshares-ui-style-guide": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#707f6f7e65e43c31a828ad02e3dda2adccf6cfc3", + "bitshares-ui-style-guide": "git+https://github.com/bitshares/bitshares-ui-style-guide.git#02a57452198f9c9b7218f38868045df599b005a5", "bitsharesjs": "^1.8.0", "browser-locale": "^1.0.3", "classnames": "^2.2.1", From b68fb6d1c1cb02994ef1d8cca05ee50d811f92f7 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 11 Jul 2018 10:29:39 +0200 Subject: [PATCH 12/69] Fix tests, use jsnext:main packages when possible --- app/App.jsx | 2 +- app/actions/AssetActions.js | 2 +- app/actions/BackupActions.js | 2 +- app/actions/MarketsActions.js | 2 +- app/actions/SignedMessageAction.js | 2 +- app/actions/WalletActions.js | 2 +- app/api/ApplicationApi.js | 2 +- app/api/DebugApi.js | 2 +- app/api/WalletApi.js | 2 +- app/components/Account/AccountAssetCreate.jsx | 2 +- app/components/Account/AccountAssetUpdate.jsx | 2 +- app/components/Account/AccountMembership.jsx | 2 +- app/components/Account/AccountOrders.jsx | 2 +- app/components/Account/AccountOverview.jsx | 2 +- app/components/Account/AccountPermissions.jsx | 2 +- .../Account/AccountPermissionsMigrate.jsx | 2 +- app/components/Account/AccountSelector.jsx | 2 +- app/components/Account/AccountTreemap.jsx | 2 +- app/components/Account/AccountVesting.jsx | 2 +- app/components/Account/AccountVoting.jsx | 2 +- app/components/Account/CreateAccount.jsx | 8 +- .../Account/CreateAccountPassword.jsx | 10 +- app/components/Account/FundFeePool.jsx | 2 +- app/components/Account/MarginPositions.jsx | 2 +- .../Account/NestedApprovalState.jsx | 2 +- app/components/Account/Proposals.jsx | 2 +- app/components/Account/RecentTransactions.jsx | 3 +- app/components/Account/VotingAccountsList.jsx | 2 +- app/components/Blockchain/Asset.jsx | 2 +- app/components/Blockchain/Fees.jsx | 2 +- app/components/Blockchain/Operation.jsx | 2 +- .../Blockchain/ProposedOperation.jsx | 2 +- app/components/Blockchain/Transaction.jsx | 2 +- .../Blockchain/TransactionConfirm.jsx | 2 +- .../BrowserNotifications.jsx | 2 +- app/components/Dashboard/AccountCard.jsx | 2 +- app/components/Dashboard/DashboardList.jsx | 2 +- app/components/Dashboard/MarketsTable.jsx | 2 +- .../Dashboard/SimpleDepositWithdraw.jsx | 2 +- .../BlockTradesBridgeDepositRequest.jsx | 2 +- .../BlockTradesGatewayDepositRequest.jsx | 2 +- .../blocktrades/WithdrawModalBlocktrades.jsx | 2 +- .../gdex/GdexWithdrawModal.jsx | 2 +- .../rudex/RuDexGatewayDepositRequest.jsx | 2 +- .../rudex/RuDexWithdrawModal.jsx | 2 +- .../winex/WinexGatewayRequest.jsx | 2 +- .../winex/WinexWithdrawModal.jsx | 2 +- app/components/Exchange/Exchange.jsx | 2 +- app/components/Exchange/ExchangeContainer.jsx | 2 +- app/components/Exchange/ExchangeHeader.jsx | 2 +- app/components/Exchange/MarketHistory.jsx | 2 +- app/components/Exchange/MarketPicker.jsx | 4 +- app/components/Exchange/MyMarkets.jsx | 2 +- app/components/Exchange/MyOpenOrders.jsx | 2 +- app/components/Exchange/tradingViewClasses.js | 2 +- app/components/Explorer/Assets.jsx | 2 +- app/components/Explorer/CommitteeMembers.jsx | 2 +- app/components/Explorer/Witnesses.jsx | 2 +- app/components/Forms/AccountNameInput.jsx | 2 +- app/components/Forms/PubKeyInput.jsx | 2 +- app/components/Layout/Footer.jsx | 2 +- app/components/Layout/Header.jsx | 2 +- app/components/Modal/BorrowModal.jsx | 107 ++++++++++---- app/components/Modal/ProposalApproveModal.jsx | 2 +- app/components/Modal/QrcodeModal.jsx | 2 +- app/components/Modal/SendModal.jsx | 2 +- app/components/Modal/SettleModal.jsx | 2 +- app/components/Modal/WithdrawModalNew.jsx | 2 +- app/components/Notifier/Notifier.jsx | 2 +- app/components/Transfer/Invoice.jsx | 2 +- app/components/Transfer/Transfer.jsx | 2 +- app/components/Utility/AssetSelector.jsx | 2 +- app/components/Utility/BindToChainState.jsx | 2 +- app/components/Utility/ChainTypes.js | 5 +- app/components/Utility/FormattedAsset.jsx | 2 +- app/components/Utility/TimeAgo.jsx | 2 +- app/components/Utility/TotalBalanceValue.jsx | 2 +- app/components/Wallet/Backup.jsx | 2 +- app/components/Wallet/BackupBrainkey.jsx | 2 +- app/components/Wallet/BrainkeyInput.jsx | 2 +- app/components/Wallet/ImportKeys.jsx | 7 +- app/components/Wallet/WalletUnlockModal.jsx | 2 +- app/dl_cli_index.js | 2 +- app/lib/chain/GenesisFilter.js | 2 +- app/lib/common/MarketClasses.js | 2 +- app/lib/common/accountHelper.js | 2 +- app/lib/common/account_utils.js | 2 +- app/lib/common/market_utils.js | 2 +- app/lib/common/permission_utils.js | 2 +- app/lib/common/trxHelper.js | 2 +- app/lib/common/utils.js | 4 +- app/lib/workers/AddressIndexWorker.js | 2 +- app/lib/workers/AesWorker.js | 2 +- app/routerTransition.js | 2 +- app/stores/AccountRefsStore.js | 2 +- app/stores/AccountStore.js | 2 +- app/stores/AddressIndex.js | 2 +- app/stores/BackupStore.js | 2 +- app/stores/BalanceClaimActiveStore.js | 2 +- app/stores/BlockchainStore.js | 2 +- app/stores/BrainkeyStore.js | 2 +- app/stores/MarketsStore.js | 2 +- app/stores/PrivateKeyStore.js | 2 +- app/stores/WalletDb.js | 2 +- app/stores/WalletManagerStore.js | 2 +- package-lock.json | 133 ++---------------- package.json | 10 +- webpack.config.js | 13 +- 108 files changed, 231 insertions(+), 267 deletions(-) diff --git a/app/App.jsx b/app/App.jsx index 95ef9730d3..63de25eeab 100644 --- a/app/App.jsx +++ b/app/App.jsx @@ -1,5 +1,5 @@ import React from "react"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import AccountStore from "stores/AccountStore"; import NotificationStore from "stores/NotificationStore"; import {withRouter} from "react-router-dom"; diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index b66249d20e..99d1a1a1a7 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -3,7 +3,7 @@ import {Apis} from "bitsharesjs-ws"; import utils from "common/utils"; import WalletApi from "api/WalletApi"; import WalletDb from "stores/WalletDb"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import big from "bignumber.js"; import {gatewayPrefixes} from "common/gateways"; let inProgress = {}; diff --git a/app/actions/BackupActions.js b/app/actions/BackupActions.js index a267163ef2..54ede0cdbf 100644 --- a/app/actions/BackupActions.js +++ b/app/actions/BackupActions.js @@ -1,7 +1,7 @@ import alt from "alt-instance"; import iDB from "idb-instance"; import {compress, decompress} from "lzma"; -import {PrivateKey, PublicKey, Aes, key} from "bitsharesjs/es"; +import {PrivateKey, PublicKey, Aes, key} from "bitsharesjs"; import WalletActions from "actions/WalletActions"; class BackupActions { diff --git a/app/actions/MarketsActions.js b/app/actions/MarketsActions.js index 35caf98f03..fabbbc26f2 100644 --- a/app/actions/MarketsActions.js +++ b/app/actions/MarketsActions.js @@ -1,7 +1,7 @@ import alt from "alt-instance"; import WalletApi from "api/WalletApi"; import WalletDb from "stores/WalletDb"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; import marketUtils from "common/market_utils"; import accountUtils from "common/account_utils"; diff --git a/app/actions/SignedMessageAction.js b/app/actions/SignedMessageAction.js index ec32805ca3..f9314d8088 100644 --- a/app/actions/SignedMessageAction.js +++ b/app/actions/SignedMessageAction.js @@ -1,6 +1,6 @@ import alt from "alt-instance"; import counterpart from "counterpart"; -import {Signature, ChainStore, PublicKey} from "bitsharesjs/es"; +import {Signature, ChainStore, PublicKey} from "bitsharesjs"; import WalletUnlockActions from "actions/WalletUnlockActions"; import WalletDb from "stores/WalletDb"; diff --git a/app/actions/WalletActions.js b/app/actions/WalletActions.js index c924878a23..58c5fb1c0a 100644 --- a/app/actions/WalletActions.js +++ b/app/actions/WalletActions.js @@ -2,7 +2,7 @@ import WalletDb from "stores/WalletDb"; import WalletUnlockActions from "actions/WalletUnlockActions"; import CachedPropertyActions from "actions/CachedPropertyActions"; import ApplicationApi from "api/ApplicationApi"; -import {TransactionBuilder, FetchChain} from "bitsharesjs/es"; +import {TransactionBuilder, FetchChain} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; import alt from "alt-instance"; import SettingsStore from "stores/SettingsStore"; diff --git a/app/api/ApplicationApi.js b/app/api/ApplicationApi.js index 63415e114d..242d778c2c 100644 --- a/app/api/ApplicationApi.js +++ b/app/api/ApplicationApi.js @@ -8,7 +8,7 @@ import { TransactionHelper, FetchChain, ChainStore -} from "bitsharesjs/es"; +} from "bitsharesjs"; import counterpart from "counterpart"; const ApplicationApi = { diff --git a/app/api/DebugApi.js b/app/api/DebugApi.js index 76f1b386c7..dd20828288 100644 --- a/app/api/DebugApi.js +++ b/app/api/DebugApi.js @@ -1,4 +1,4 @@ -import {SerializerValidation, types} from "bitsharesjs/es"; +import {SerializerValidation, types} from "bitsharesjs"; var config = require("chain/serializer_config"); class DebugApi { diff --git a/app/api/WalletApi.js b/app/api/WalletApi.js index c1ddf0e144..13c26af5fe 100644 --- a/app/api/WalletApi.js +++ b/app/api/WalletApi.js @@ -2,7 +2,7 @@ import { SerializerValidation, TransactionBuilder, TransactionHelper -} from "bitsharesjs/es"; +} from "bitsharesjs"; import ApplicationApi from "./ApplicationApi"; const WalletApi = { diff --git a/app/components/Account/AccountAssetCreate.jsx b/app/components/Account/AccountAssetCreate.jsx index 08f1dc75bf..3417ddf2ac 100644 --- a/app/components/Account/AccountAssetCreate.jsx +++ b/app/components/Account/AccountAssetCreate.jsx @@ -4,7 +4,7 @@ import classnames from "classnames"; import AssetActions from "actions/AssetActions"; import HelpContent from "../Utility/HelpContent"; import utils from "common/utils"; -import {ChainStore, ChainValidation} from "bitsharesjs/es"; +import {ChainStore, ChainValidation} from "bitsharesjs"; import FormattedAsset from "../Utility/FormattedAsset"; import counterpart from "counterpart"; import ChainTypes from "../Utility/ChainTypes"; diff --git a/app/components/Account/AccountAssetUpdate.jsx b/app/components/Account/AccountAssetUpdate.jsx index ee4bdb1cc0..4eb6297d4c 100644 --- a/app/components/Account/AccountAssetUpdate.jsx +++ b/app/components/Account/AccountAssetUpdate.jsx @@ -4,7 +4,7 @@ import classnames from "classnames"; import AssetActions from "actions/AssetActions"; import HelpContent from "../Utility/HelpContent"; import utils from "common/utils"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import FormattedAsset from "../Utility/FormattedAsset"; import FormattedFee from "../Utility/FormattedFee"; import counterpart from "counterpart"; diff --git a/app/components/Account/AccountMembership.jsx b/app/components/Account/AccountMembership.jsx index 130f185712..3ac7b0ee9a 100644 --- a/app/components/Account/AccountMembership.jsx +++ b/app/components/Account/AccountMembership.jsx @@ -1,7 +1,7 @@ import React from "react"; import {Link} from "react-router-dom"; import Translate from "react-translate-component"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; import Statistics from "./Statistics"; diff --git a/app/components/Account/AccountOrders.jsx b/app/components/Account/AccountOrders.jsx index 595d44ddc1..f815d065ca 100644 --- a/app/components/Account/AccountOrders.jsx +++ b/app/components/Account/AccountOrders.jsx @@ -2,7 +2,7 @@ import React from "react"; import {OrderRow, TableHeader} from "../Exchange/MyOpenOrders"; import counterpart from "counterpart"; import MarketsActions from "actions/MarketsActions"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {LimitOrder} from "common/MarketClasses"; import {connect} from "alt-react"; import SettingsStore from "stores/SettingsStore"; diff --git a/app/components/Account/AccountOverview.jsx b/app/components/Account/AccountOverview.jsx index 7e9b4d45ee..f53c7bcf26 100644 --- a/app/components/Account/AccountOverview.jsx +++ b/app/components/Account/AccountOverview.jsx @@ -6,7 +6,7 @@ import AssetName from "../Utility/AssetName"; import MarginPositions from "./MarginPositions"; import {RecentTransactions} from "./RecentTransactions"; import Proposals from "components/Account/Proposals"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import SettingsActions from "actions/SettingsActions"; import utils from "common/utils"; diff --git a/app/components/Account/AccountPermissions.jsx b/app/components/Account/AccountPermissions.jsx index 4a3d739b14..98ec20bd1b 100644 --- a/app/components/Account/AccountPermissions.jsx +++ b/app/components/Account/AccountPermissions.jsx @@ -5,7 +5,7 @@ import counterpart from "counterpart"; import utils from "common/utils"; import accountUtils from "common/account_utils"; import ApplicationApi from "api/ApplicationApi"; -import {PublicKey} from "bitsharesjs/es"; +import {PublicKey} from "bitsharesjs"; import AccountPermissionsList from "./AccountPermissionsList"; import AccountPermissionsMigrate from "./AccountPermissionsMigrate"; import PubKeyInput from "../Forms/PubKeyInput"; diff --git a/app/components/Account/AccountPermissionsMigrate.jsx b/app/components/Account/AccountPermissionsMigrate.jsx index 26e99a9a45..1a55c6af89 100644 --- a/app/components/Account/AccountPermissionsMigrate.jsx +++ b/app/components/Account/AccountPermissionsMigrate.jsx @@ -3,7 +3,7 @@ import PasswordInput from "./../Forms/PasswordInput"; import WalletDb from "stores/WalletDb"; import Translate from "react-translate-component"; import counterpart from "counterpart"; -import {key} from "bitsharesjs/es"; +import {key} from "bitsharesjs"; export default class AccountPermissionsMigrate extends React.Component { constructor() { diff --git a/app/components/Account/AccountSelector.jsx b/app/components/Account/AccountSelector.jsx index 87e7b7afec..f86b2a885d 100644 --- a/app/components/Account/AccountSelector.jsx +++ b/app/components/Account/AccountSelector.jsx @@ -5,7 +5,7 @@ import AccountImage from "../Account/AccountImage"; import AccountStore from "stores/AccountStore"; import AccountActions from "actions/AccountActions"; import Translate from "react-translate-component"; -import {ChainStore, PublicKey, ChainValidation} from "bitsharesjs/es"; +import {ChainStore, PublicKey, ChainValidation} from "bitsharesjs"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; import classnames from "classnames"; diff --git a/app/components/Account/AccountTreemap.jsx b/app/components/Account/AccountTreemap.jsx index 8036bf3632..a7dd6ee3a0 100644 --- a/app/components/Account/AccountTreemap.jsx +++ b/app/components/Account/AccountTreemap.jsx @@ -4,7 +4,7 @@ import Treemap from "highcharts/modules/treemap"; import Heatmap from "highcharts/modules/heatmap"; import utils from "common/utils"; import ChainTypes from "../Utility/ChainTypes"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import BindToChainState from "../Utility/BindToChainState"; import AltContainer from "alt-container"; import MarketUtils from "common/market_utils"; diff --git a/app/components/Account/AccountVesting.jsx b/app/components/Account/AccountVesting.jsx index 4c08147205..b908f76086 100644 --- a/app/components/Account/AccountVesting.jsx +++ b/app/components/Account/AccountVesting.jsx @@ -1,7 +1,7 @@ import React from "react"; import Translate from "react-translate-component"; import FormattedAsset from "../Utility/FormattedAsset"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import utils from "common/utils"; import WalletActions from "actions/WalletActions"; import {Apis} from "bitsharesjs-ws"; diff --git a/app/components/Account/AccountVoting.jsx b/app/components/Account/AccountVoting.jsx index a087f2b8a3..1bb9d77ccb 100644 --- a/app/components/Account/AccountVoting.jsx +++ b/app/components/Account/AccountVoting.jsx @@ -2,7 +2,7 @@ import React from "react"; import Immutable from "immutable"; import Translate from "react-translate-component"; import accountUtils from "common/account_utils"; -import {ChainStore, FetchChainObjects} from "bitsharesjs/es"; +import {ChainStore, FetchChainObjects} from "bitsharesjs"; import WorkerApproval from "./WorkerApproval"; import VotingAccountsList from "./VotingAccountsList"; import cnames from "classnames"; diff --git a/app/components/Account/CreateAccount.jsx b/app/components/Account/CreateAccount.jsx index a71c654821..ed51ba7b82 100644 --- a/app/components/Account/CreateAccount.jsx +++ b/app/components/Account/CreateAccount.jsx @@ -14,7 +14,7 @@ import TransactionConfirmStore from "stores/TransactionConfirmStore"; import LoadingIndicator from "../LoadingIndicator"; import WalletActions from "actions/WalletActions"; import Translate from "react-translate-component"; -import {ChainStore, FetchChain} from "bitsharesjs/es"; +import {ChainStore, FetchChain} from "bitsharesjs"; import {BackupCreate} from "../Wallet/Backup"; import ReactTooltip from "react-tooltip"; import utils from "common/utils"; @@ -546,7 +546,11 @@ class CreateAccount extends React.Component { let {step} = this.state; return ( -
    +
    {step !== 1 ? (

    +

    {step === 2 ? (

    value) => value => that.setState({[key]: transform(value)}); diff --git a/app/components/Account/MarginPositions.jsx b/app/components/Account/MarginPositions.jsx index 4d81b4d35f..66eab53af4 100644 --- a/app/components/Account/MarginPositions.jsx +++ b/app/components/Account/MarginPositions.jsx @@ -7,7 +7,7 @@ import AssetWrapper from "../Utility/AssetWrapper"; import AssetName from "../Utility/AssetName"; import BorrowModal from "../Modal/BorrowModal"; import WalletApi from "api/WalletApi"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import WalletDb from "stores/WalletDb"; import Translate from "react-translate-component"; import utils from "common/utils"; diff --git a/app/components/Account/NestedApprovalState.jsx b/app/components/Account/NestedApprovalState.jsx index 2fb7a6ff68..36305d894c 100644 --- a/app/components/Account/NestedApprovalState.jsx +++ b/app/components/Account/NestedApprovalState.jsx @@ -4,7 +4,7 @@ import BindToChainState from "../Utility/BindToChainState"; import LinkToAccountById from "../Utility/LinkToAccountById"; import pu from "common/permission_utils"; import {cloneDeep} from "lodash-es"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import { AuthorityDepthOverflowWarning, ChildAuthorityDepthOverflowWarning, diff --git a/app/components/Account/Proposals.jsx b/app/components/Account/Proposals.jsx index 51e668f6bb..22ff160c1c 100644 --- a/app/components/Account/Proposals.jsx +++ b/app/components/Account/Proposals.jsx @@ -11,7 +11,7 @@ import ProposalApproveModal, { finalRequiredPerms } from "../Modal/ProposalApproveModal"; import NestedApprovalState from "../Account/NestedApprovalState"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import counterpart from "counterpart"; import pu from "common/permission_utils"; import LinkToAccountById from "../Utility/LinkToAccountById"; diff --git a/app/components/Account/RecentTransactions.jsx b/app/components/Account/RecentTransactions.jsx index 20bfcb6c32..078053dd64 100644 --- a/app/components/Account/RecentTransactions.jsx +++ b/app/components/Account/RecentTransactions.jsx @@ -5,7 +5,7 @@ import Operation from "../Blockchain/Operation"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; import utils from "common/utils"; -import {ChainTypes as grapheneChainTypes} from "bitsharesjs/es"; +import {ChainTypes as grapheneChainTypes} from "bitsharesjs"; import TransitionWrapper from "../Utility/TransitionWrapper"; import ps from "perfect-scrollbar"; import counterpart from "counterpart"; @@ -300,7 +300,6 @@ class RecentTransactions extends React.Component { ]; display_history.push( - {historyCount > 0 ? ( diff --git a/app/components/Account/VotingAccountsList.jsx b/app/components/Account/VotingAccountsList.jsx index 527113b8be..53e32bd8c9 100644 --- a/app/components/Account/VotingAccountsList.jsx +++ b/app/components/Account/VotingAccountsList.jsx @@ -2,7 +2,7 @@ import React from "react"; import AccountSelector from "./AccountSelector"; import Translate from "react-translate-component"; import Icon from "../Icon/Icon"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ChainTypes from "../Utility/ChainTypes"; import FormattedAsset from "../Utility/FormattedAsset"; import BindToChainState from "../Utility/BindToChainState"; diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index 5a1972766c..e2cfa81e6b 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -11,7 +11,7 @@ import HelpContent from "../Utility/HelpContent"; import assetUtils from "common/asset_utils"; import utils from "common/utils"; import FormattedTime from "../Utility/FormattedTime"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; import {Tabs, Tab} from "../Utility/Tabs"; import {CallOrder, FeedPrice} from "common/MarketClasses"; diff --git a/app/components/Blockchain/Fees.jsx b/app/components/Blockchain/Fees.jsx index cf62ec0c09..8744e94287 100644 --- a/app/components/Blockchain/Fees.jsx +++ b/app/components/Blockchain/Fees.jsx @@ -8,7 +8,7 @@ import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; import FormattedAsset from "../Utility/FormattedAsset"; import {EquivalentValueComponent} from "../Utility/EquivalentValueComponent"; -import {ChainStore, ChainTypes as grapheneChainTypes} from "bitsharesjs/es"; +import {ChainStore, ChainTypes as grapheneChainTypes} from "bitsharesjs"; const {operations} = grapheneChainTypes; let ops = Object.keys(operations); diff --git a/app/components/Blockchain/Operation.jsx b/app/components/Blockchain/Operation.jsx index 665c6ff16f..d36aa676e6 100644 --- a/app/components/Blockchain/Operation.jsx +++ b/app/components/Blockchain/Operation.jsx @@ -11,7 +11,7 @@ import LinkToAssetById from "../Utility/LinkToAssetById"; import BindToChainState from "../Utility/BindToChainState"; import ChainTypes from "../Utility/ChainTypes"; import TranslateWithLinks from "../Utility/TranslateWithLinks"; -import {ChainStore, ChainTypes as grapheneChainTypes} from "bitsharesjs/es"; +import {ChainStore, ChainTypes as grapheneChainTypes} from "bitsharesjs"; import account_constants from "chain/account_constants"; import MemoText from "./MemoText"; import ProposedOperation from "./ProposedOperation"; diff --git a/app/components/Blockchain/ProposedOperation.jsx b/app/components/Blockchain/ProposedOperation.jsx index 5b53fccc8b..48f3301baf 100644 --- a/app/components/Blockchain/ProposedOperation.jsx +++ b/app/components/Blockchain/ProposedOperation.jsx @@ -10,7 +10,7 @@ import LinkToAccountById from "../Utility/LinkToAccountById"; import LinkToAssetById from "../Utility/LinkToAssetById"; import BindToChainState from "../Utility/BindToChainState"; import FormattedPrice from "../Utility/FormattedPrice"; -import {ChainStore, ChainTypes as grapheneChainTypes} from "bitsharesjs/es"; +import {ChainStore, ChainTypes as grapheneChainTypes} from "bitsharesjs"; import account_constants from "chain/account_constants"; import MemoText from "./MemoText"; import TranslateWithLinks from "../Utility/TranslateWithLinks"; diff --git a/app/components/Blockchain/Transaction.jsx b/app/components/Blockchain/Transaction.jsx index beda0128bb..b45bba7c8e 100644 --- a/app/components/Blockchain/Transaction.jsx +++ b/app/components/Blockchain/Transaction.jsx @@ -16,7 +16,7 @@ import Icon from "../Icon/Icon"; import PrivateKeyStore from "stores/PrivateKeyStore"; import WalletUnlockActions from "actions/WalletUnlockActions"; import ProposedOperation from "./ProposedOperation"; -import {ChainTypes} from "bitsharesjs/es"; +import {ChainTypes} from "bitsharesjs"; let {operations} = ChainTypes; import ReactTooltip from "react-tooltip"; import moment from "moment"; diff --git a/app/components/Blockchain/TransactionConfirm.jsx b/app/components/Blockchain/TransactionConfirm.jsx index 24fb49ed3f..d3c5e5a8f4 100644 --- a/app/components/Blockchain/TransactionConfirm.jsx +++ b/app/components/Blockchain/TransactionConfirm.jsx @@ -11,7 +11,7 @@ import LoadingIndicator from "../LoadingIndicator"; import WalletDb from "stores/WalletDb"; import AccountStore from "stores/AccountStore"; import AccountSelect from "components/Forms/AccountSelect"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import utils from "common/utils"; import Operation from "components/Blockchain/Operation"; import notify from "actions/NotificationActions"; diff --git a/app/components/BrowserNotifications/BrowserNotifications.jsx b/app/components/BrowserNotifications/BrowserNotifications.jsx index 09b600291a..7a7889193e 100644 --- a/app/components/BrowserNotifications/BrowserNotifications.jsx +++ b/app/components/BrowserNotifications/BrowserNotifications.jsx @@ -1,7 +1,7 @@ import React from "react"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; -import {ChainTypes as GraphChainTypes, ChainStore} from "bitsharesjs/es"; +import {ChainTypes as GraphChainTypes, ChainStore} from "bitsharesjs"; import counterpart from "counterpart"; import utils from "common/utils"; import Notify from "notifyjs"; diff --git a/app/components/Dashboard/AccountCard.jsx b/app/components/Dashboard/AccountCard.jsx index d5298dd654..b2ae72c44c 100644 --- a/app/components/Dashboard/AccountCard.jsx +++ b/app/components/Dashboard/AccountCard.jsx @@ -4,7 +4,7 @@ import AccountImage from "../Account/AccountImage"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; import AccountStore from "stores/AccountStore"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {withRouter} from "react-router-dom"; /** diff --git a/app/components/Dashboard/DashboardList.jsx b/app/components/Dashboard/DashboardList.jsx index de312d2e0e..1fdd7c9616 100644 --- a/app/components/Dashboard/DashboardList.jsx +++ b/app/components/Dashboard/DashboardList.jsx @@ -10,7 +10,7 @@ import BindToChainState from "../Utility/BindToChainState"; import SettingsActions from "actions/SettingsActions"; import AccountActions from "actions/AccountActions"; import Icon from "../Icon/Icon"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import TotalBalanceValue from "../Utility/TotalBalanceValue"; import AccountStore from "stores/AccountStore"; import counterpart from "counterpart"; diff --git a/app/components/Dashboard/MarketsTable.jsx b/app/components/Dashboard/MarketsTable.jsx index c51282e7db..39c4d79a97 100644 --- a/app/components/Dashboard/MarketsTable.jsx +++ b/app/components/Dashboard/MarketsTable.jsx @@ -1,7 +1,7 @@ import React from "react"; import {connect} from "alt-react"; import {Link} from "react-router-dom"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import Translate from "react-translate-component"; import cnames from "classnames"; import MarketsStore from "stores/MarketsStore"; diff --git a/app/components/Dashboard/SimpleDepositWithdraw.jsx b/app/components/Dashboard/SimpleDepositWithdraw.jsx index 3a2d6c0e77..83deede125 100644 --- a/app/components/Dashboard/SimpleDepositWithdraw.jsx +++ b/app/components/Dashboard/SimpleDepositWithdraw.jsx @@ -20,7 +20,7 @@ import Icon from "../Icon/Icon"; import LoadingIndicator from "../LoadingIndicator"; import {checkFeeStatusAsync, checkBalance} from "common/trxHelper"; import AssetName from "../Utility/AssetName"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {debounce} from "lodash-es"; import {DecimalChecker} from "../Exchange/ExchangeInput"; import {openledgerAPIs} from "api/apiConfig"; diff --git a/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx b/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx index 9cd653ae28..777365b179 100644 --- a/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx +++ b/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx @@ -14,7 +14,7 @@ import {blockTradesAPIs} from "api/apiConfig"; import {debounce} from "lodash-es"; import {checkFeeStatusAsync, checkBalance} from "common/trxHelper"; import {Asset} from "common/MarketClasses"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {getConversionJson} from "common/gatewayMethods"; import PropTypes from "prop-types"; diff --git a/app/components/DepositWithdraw/blocktrades/BlockTradesGatewayDepositRequest.jsx b/app/components/DepositWithdraw/blocktrades/BlockTradesGatewayDepositRequest.jsx index 431865beea..ae58996486 100644 --- a/app/components/DepositWithdraw/blocktrades/BlockTradesGatewayDepositRequest.jsx +++ b/app/components/DepositWithdraw/blocktrades/BlockTradesGatewayDepositRequest.jsx @@ -1,6 +1,6 @@ import React from "react"; import Translate from "react-translate-component"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ChainTypes from "components/Utility/ChainTypes"; import BindToChainState from "components/Utility/BindToChainState"; import WithdrawModalBlocktrades from "./WithdrawModalBlocktrades"; diff --git a/app/components/DepositWithdraw/blocktrades/WithdrawModalBlocktrades.jsx b/app/components/DepositWithdraw/blocktrades/WithdrawModalBlocktrades.jsx index c87e212942..6af44e5b0a 100644 --- a/app/components/DepositWithdraw/blocktrades/WithdrawModalBlocktrades.jsx +++ b/app/components/DepositWithdraw/blocktrades/WithdrawModalBlocktrades.jsx @@ -10,7 +10,7 @@ import AmountSelector from "components/Utility/AmountSelector"; import AccountActions from "actions/AccountActions"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; import {validateAddress, WithdrawAddresses} from "common/gatewayMethods"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import Modal from "react-foundation-apps/src/modal"; import {checkFeeStatusAsync, checkBalance} from "common/trxHelper"; import {debounce} from "lodash-es"; diff --git a/app/components/DepositWithdraw/gdex/GdexWithdrawModal.jsx b/app/components/DepositWithdraw/gdex/GdexWithdrawModal.jsx index 67061c2d10..180c595d1b 100644 --- a/app/components/DepositWithdraw/gdex/GdexWithdrawModal.jsx +++ b/app/components/DepositWithdraw/gdex/GdexWithdrawModal.jsx @@ -10,7 +10,7 @@ import AmountSelector from "components/Utility/AmountSelector"; import AccountActions from "actions/AccountActions"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; import {validateAddress, WithdrawAddresses} from "common/gdexMethods"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import Modal from "react-foundation-apps/src/modal"; import {checkFeeStatusAsync, checkBalance} from "common/trxHelper"; import {Asset, Price} from "common/MarketClasses"; diff --git a/app/components/DepositWithdraw/rudex/RuDexGatewayDepositRequest.jsx b/app/components/DepositWithdraw/rudex/RuDexGatewayDepositRequest.jsx index d64af633a3..a5784a8f1d 100644 --- a/app/components/DepositWithdraw/rudex/RuDexGatewayDepositRequest.jsx +++ b/app/components/DepositWithdraw/rudex/RuDexGatewayDepositRequest.jsx @@ -1,6 +1,6 @@ import React from "react"; import Translate from "react-translate-component"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ChainTypes from "components/Utility/ChainTypes"; import BindToChainState from "components/Utility/BindToChainState"; import RuDexWithdrawModal from "./RuDexWithdrawModal"; diff --git a/app/components/DepositWithdraw/rudex/RuDexWithdrawModal.jsx b/app/components/DepositWithdraw/rudex/RuDexWithdrawModal.jsx index 80823cdd11..92e21729b0 100644 --- a/app/components/DepositWithdraw/rudex/RuDexWithdrawModal.jsx +++ b/app/components/DepositWithdraw/rudex/RuDexWithdrawModal.jsx @@ -10,7 +10,7 @@ import AmountSelector from "components/Utility/AmountSelector"; import AccountActions from "actions/AccountActions"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; import {validateAddress, WithdrawAddresses} from "common/RuDexMethods"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import Modal from "react-foundation-apps/src/modal"; import {checkFeeStatusAsync, checkBalance} from "common/trxHelper"; import {Price, Asset} from "common/MarketClasses"; diff --git a/app/components/DepositWithdraw/winex/WinexGatewayRequest.jsx b/app/components/DepositWithdraw/winex/WinexGatewayRequest.jsx index 9e9a5886b5..cd14c72854 100644 --- a/app/components/DepositWithdraw/winex/WinexGatewayRequest.jsx +++ b/app/components/DepositWithdraw/winex/WinexGatewayRequest.jsx @@ -1,6 +1,6 @@ import React from "react"; import Translate from "react-translate-component"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ChainTypes from "components/Utility/ChainTypes"; import BindToChainState from "components/Utility/BindToChainState"; import WinexWithdrawModal from "components/DepositWithdraw/winex/WinexWithdrawModal"; diff --git a/app/components/DepositWithdraw/winex/WinexWithdrawModal.jsx b/app/components/DepositWithdraw/winex/WinexWithdrawModal.jsx index 5b129e6fda..4655a1f346 100644 --- a/app/components/DepositWithdraw/winex/WinexWithdrawModal.jsx +++ b/app/components/DepositWithdraw/winex/WinexWithdrawModal.jsx @@ -10,7 +10,7 @@ import AmountSelector from "components/Utility/AmountSelector"; import AccountActions from "actions/AccountActions"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; import {validateAddress, WithdrawAddresses} from "common/gatewayMethods"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import Modal from "react-foundation-apps/src/modal"; import {checkFeeStatusAsync, checkBalance} from "common/trxHelper"; import {Asset} from "common/MarketClasses"; diff --git a/app/components/Exchange/Exchange.jsx b/app/components/Exchange/Exchange.jsx index f762248027..bd724eb7e0 100644 --- a/app/components/Exchange/Exchange.jsx +++ b/app/components/Exchange/Exchange.jsx @@ -17,7 +17,7 @@ import BorrowModal from "../Modal/BorrowModal"; import notify from "actions/NotificationActions"; import AccountNotifications from "../Notifier/NotifierContainer"; import Ps from "perfect-scrollbar"; -import {ChainStore, FetchChain} from "bitsharesjs/es"; +import {ChainStore, FetchChain} from "bitsharesjs"; import SettingsActions from "actions/SettingsActions"; import cnames from "classnames"; import market_utils from "common/market_utils"; diff --git a/app/components/Exchange/ExchangeContainer.jsx b/app/components/Exchange/ExchangeContainer.jsx index 8e2a19de89..f22cacc003 100644 --- a/app/components/Exchange/ExchangeContainer.jsx +++ b/app/components/Exchange/ExchangeContainer.jsx @@ -8,7 +8,7 @@ import WalletUnlockStore from "stores/WalletUnlockStore"; import AltContainer from "alt-container"; import Exchange from "./Exchange"; import ChainTypes from "../Utility/ChainTypes"; -import {EmitterInstance} from "bitsharesjs/es"; +import {EmitterInstance} from "bitsharesjs"; import BindToChainState from "../Utility/BindToChainState"; import MarketsActions from "actions/MarketsActions"; import {DataFeed} from "components/Exchange/tradingViewClasses"; diff --git a/app/components/Exchange/ExchangeHeader.jsx b/app/components/Exchange/ExchangeHeader.jsx index 99110ef0fe..2b85ce9ab4 100644 --- a/app/components/Exchange/ExchangeHeader.jsx +++ b/app/components/Exchange/ExchangeHeader.jsx @@ -7,7 +7,7 @@ import SettingsActions from "actions/SettingsActions"; import PriceStatWithLabel from "./PriceStatWithLabel"; import Translate from "react-translate-component"; import counterpart from "counterpart"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ExchangeHeaderCollateral from "./ExchangeHeaderCollateral"; import BaseModal from "../Modal/BaseModal"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; diff --git a/app/components/Exchange/MarketHistory.jsx b/app/components/Exchange/MarketHistory.jsx index 5e160c0028..b38c78f991 100644 --- a/app/components/Exchange/MarketHistory.jsx +++ b/app/components/Exchange/MarketHistory.jsx @@ -11,7 +11,7 @@ import SettingsStore from "stores/SettingsStore"; import {connect} from "alt-react"; import TransitionWrapper from "../Utility/TransitionWrapper"; import AssetName from "../Utility/AssetName"; -import {ChainTypes as grapheneChainTypes} from "bitsharesjs/es"; +import {ChainTypes as grapheneChainTypes} from "bitsharesjs"; const {operations} = grapheneChainTypes; import BlockDate from "../Utility/BlockDate"; import counterpart from "counterpart"; diff --git a/app/components/Exchange/MarketPicker.jsx b/app/components/Exchange/MarketPicker.jsx index 4ab04352dc..e5fc22dddc 100644 --- a/app/components/Exchange/MarketPicker.jsx +++ b/app/components/Exchange/MarketPicker.jsx @@ -6,11 +6,11 @@ import {Link} from "react-router-dom"; import AssetName from "../Utility/AssetName"; import Icon from "../Icon/Icon"; import {debounce} from "lodash-es"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import Translate from "react-translate-component"; import LoadingIndicator from "../LoadingIndicator"; import AssetActions from "actions/AssetActions"; -import {ChainValidation} from "bitsharesjs/es"; +import {ChainValidation} from "bitsharesjs"; import counterpart from "counterpart"; import utils from "common/utils"; import {hasGatewayPrefix} from "common/gatewayUtils"; diff --git a/app/components/Exchange/MyMarkets.jsx b/app/components/Exchange/MyMarkets.jsx index c73f1275d5..993c63b1ad 100644 --- a/app/components/Exchange/MyMarkets.jsx +++ b/app/components/Exchange/MyMarkets.jsx @@ -18,7 +18,7 @@ import {debounce} from "lodash-es"; import AssetSelector from "../Utility/AssetSelector"; import counterpart from "counterpart"; import LoadingIndicator from "../LoadingIndicator"; -import {ChainValidation} from "bitsharesjs/es"; +import {ChainValidation} from "bitsharesjs"; import debounceRender from "react-debounce-render"; class MarketGroup extends React.Component { diff --git a/app/components/Exchange/MyOpenOrders.jsx b/app/components/Exchange/MyOpenOrders.jsx index 60795236f0..3d7ca690d2 100644 --- a/app/components/Exchange/MyOpenOrders.jsx +++ b/app/components/Exchange/MyOpenOrders.jsx @@ -12,7 +12,7 @@ import SettingsActions from "actions/SettingsActions"; import AssetName from "../Utility/AssetName"; import cnames from "classnames"; import Icon from "../Icon/Icon"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {LimitOrder, CallOrder} from "common/MarketClasses"; import {EquivalentValueComponent} from "../Utility/EquivalentValueComponent"; import {MarketPrice} from "../Utility/MarketPrice"; diff --git a/app/components/Exchange/tradingViewClasses.js b/app/components/Exchange/tradingViewClasses.js index 61791507ee..d30b697103 100644 --- a/app/components/Exchange/tradingViewClasses.js +++ b/app/components/Exchange/tradingViewClasses.js @@ -1,5 +1,5 @@ import MarketsStore from "stores/MarketsStore"; -import {FetchChain} from "bitsharesjs/es"; +import {FetchChain} from "bitsharesjs"; import moment from "moment-timezone"; import MarketsActions from "actions/MarketsActions"; import {getGatewayName} from "common/gatewayUtils"; diff --git a/app/components/Explorer/Assets.jsx b/app/components/Explorer/Assets.jsx index 86f097b00f..cf75e262a0 100644 --- a/app/components/Explorer/Assets.jsx +++ b/app/components/Explorer/Assets.jsx @@ -10,7 +10,7 @@ import assetUtils from "common/asset_utils"; import counterpart from "counterpart"; import FormattedAsset from "../Utility/FormattedAsset"; import AssetName from "../Utility/AssetName"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import cnames from "classnames"; import utils from "common/utils"; import LoadingIndicator from "../LoadingIndicator"; diff --git a/app/components/Explorer/CommitteeMembers.jsx b/app/components/Explorer/CommitteeMembers.jsx index a442eec772..aa4436e6ce 100644 --- a/app/components/Explorer/CommitteeMembers.jsx +++ b/app/components/Explorer/CommitteeMembers.jsx @@ -3,7 +3,7 @@ import Immutable from "immutable"; import AccountImage from "../Account/AccountImage"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import FormattedAsset from "../Utility/FormattedAsset"; import Translate from "react-translate-component"; import {connect} from "alt-react"; diff --git a/app/components/Explorer/Witnesses.jsx b/app/components/Explorer/Witnesses.jsx index f784f196ae..0e00899564 100644 --- a/app/components/Explorer/Witnesses.jsx +++ b/app/components/Explorer/Witnesses.jsx @@ -3,7 +3,7 @@ import Immutable from "immutable"; import AccountImage from "../Account/AccountImage"; import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import FormattedAsset from "../Utility/FormattedAsset"; import Translate from "react-translate-component"; import TimeAgo from "../Utility/TimeAgo"; diff --git a/app/components/Forms/AccountNameInput.jsx b/app/components/Forms/AccountNameInput.jsx index 645ad72f1c..0401e20815 100644 --- a/app/components/Forms/AccountNameInput.jsx +++ b/app/components/Forms/AccountNameInput.jsx @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import classNames from "classnames"; import AccountActions from "actions/AccountActions"; import AccountStore from "stores/AccountStore"; -import {ChainValidation} from "bitsharesjs/es"; +import {ChainValidation} from "bitsharesjs"; import Translate from "react-translate-component"; import counterpart from "counterpart"; import AltContainer from "alt-container"; diff --git a/app/components/Forms/PubKeyInput.jsx b/app/components/Forms/PubKeyInput.jsx index 4ca5c62330..a76797db5a 100644 --- a/app/components/Forms/PubKeyInput.jsx +++ b/app/components/Forms/PubKeyInput.jsx @@ -2,7 +2,7 @@ import React from "react"; import classnames from "classnames"; import Translate from "react-translate-component"; import PrivateKeyView from "components/PrivateKeyView"; -import {PublicKey} from "bitsharesjs/es"; +import {PublicKey} from "bitsharesjs"; import Icon from "../Icon/Icon"; import PrivateKeyStore from "stores/PrivateKeyStore"; import PropTypes from "prop-types"; diff --git a/app/components/Layout/Footer.jsx b/app/components/Layout/Footer.jsx index f8f418bea9..462e35d4e1 100644 --- a/app/components/Layout/Footer.jsx +++ b/app/components/Layout/Footer.jsx @@ -18,7 +18,7 @@ import LoadingIndicator from "../LoadingIndicator"; import counterpart from "counterpart"; import ConfirmModal from "../Modal/ConfirmModal"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import ifvisible from "ifvisible"; import {getWalletName} from "branding"; diff --git a/app/components/Layout/Header.jsx b/app/components/Layout/Header.jsx index c1e0f23d17..ee07e21aa5 100644 --- a/app/components/Layout/Header.jsx +++ b/app/components/Layout/Header.jsx @@ -23,7 +23,7 @@ import ReactTooltip from "react-tooltip"; import {Apis} from "bitsharesjs-ws"; import notify from "actions/NotificationActions"; import AccountImage from "../Account/AccountImage"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import WithdrawModal from "../Modal/WithdrawModalNew"; import {List} from "immutable"; import DropDownMenu from "./HeaderDropdown"; diff --git a/app/components/Modal/BorrowModal.jsx b/app/components/Modal/BorrowModal.jsx index 6a215e0b27..83060dd7ce 100755 --- a/app/components/Modal/BorrowModal.jsx +++ b/app/components/Modal/BorrowModal.jsx @@ -18,7 +18,7 @@ import FormattedPrice from "../Utility/FormattedPrice"; import counterpart from "counterpart"; import HelpContent from "../Utility/HelpContent"; import Immutable from "immutable"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {List} from "immutable"; import Icon from "../Icon/Icon"; @@ -136,11 +136,13 @@ class BorrowModalContent extends React.Component { } _getMaintenanceRatio() { - return this.props.quote_asset.getIn([ - "bitasset", - "current_feed", - "maintenance_collateral_ratio" - ]) / 1000; + return ( + this.props.quote_asset.getIn([ + "bitasset", + "current_feed", + "maintenance_collateral_ratio" + ]) / 1000 + ); } confirmClicked(e) { @@ -150,7 +152,7 @@ class BorrowModalContent extends React.Component { toggleLockedCR(e) { e.preventDefault(); - this.setState({lockedCR: !this.state.lockedCR ? true : false}) + this.setState({lockedCR: !this.state.lockedCR ? true : false}); } _onBorrowChange(e) { @@ -209,7 +211,7 @@ class BorrowModalContent extends React.Component { let short_amount; let collateral; - if(this.state.lockedCR) { + if (this.state.lockedCR) { short_amount = (this.state.collateral * feed_price / ratio).toFixed( this.props.backing_asset.get("precision") ); @@ -218,7 +220,7 @@ class BorrowModalContent extends React.Component { short_amount = this.state.short_amount; collateral = (this.state.short_amount / feed_price * ratio).toFixed( this.props.backing_asset.get("precision") - ) + ); } let newState = { @@ -334,8 +336,12 @@ class BorrowModalContent extends React.Component { : this.props.backing_balance.toJS(); let maintenanceRatio = this._getMaintenanceRatio(); - let originalCR = this._getCollateralRatio(original_position.debt, original_position.collateral); - let isOriginalBelowMCR = original_position.collateral > 0 && originalCR < maintenanceRatio; + let originalCR = this._getCollateralRatio( + original_position.debt, + original_position.collateral + ); + let isOriginalBelowMCR = + original_position.collateral > 0 && originalCR < maintenanceRatio; if ( parseFloat(newState.collateral) - original_position.collateral > @@ -348,25 +354,40 @@ class BorrowModalContent extends React.Component { "borrow.errors.collateral" ); } - + // let sqp = this.props.quote_asset.getIn(["bitasset", "current_feed", "maximum_short_squeeze_ratio"]) / 1000; - if(isOriginalBelowMCR && newState.short_amount > original_position.debt) { + if ( + isOriginalBelowMCR && + newState.short_amount > original_position.debt + ) { errors.below_maintenance = counterpart.translate( "borrow.errors.increased_debt_on_margin_call" ); - } - else if(isOriginalBelowMCR && parseFloat(newState.collateral_ratio) <= parseFloat(originalCR)) { + } else if ( + isOriginalBelowMCR && + parseFloat(newState.collateral_ratio) <= parseFloat(originalCR) + ) { errors.below_maintenance = counterpart.translate( - "borrow.errors.below_ratio_mcr_update", {ocr: originalCR.toFixed(4)} + "borrow.errors.below_ratio_mcr_update", + {ocr: originalCR.toFixed(4)} ); - } else if(!isOriginalBelowMCR && parseFloat(newState.collateral_ratio) < (this._isPredictionMarket(this.props) ? 1 : maintenanceRatio)) { + } else if ( + !isOriginalBelowMCR && + parseFloat(newState.collateral_ratio) < + (this._isPredictionMarket(this.props) ? 1 : maintenanceRatio) + ) { errors.below_maintenance = counterpart.translate( - "borrow.errors.below", {mr: maintenanceRatio} + "borrow.errors.below", + {mr: maintenanceRatio} ); - } else if(parseFloat(newState.collateral_ratio) < (this._isPredictionMarket(this.props) ? 1 : maintenanceRatio + 0.5)) { + } else if ( + parseFloat(newState.collateral_ratio) < + (this._isPredictionMarket(this.props) ? 1 : maintenanceRatio + 0.5) + ) { errors.close_maintenance = counterpart.translate( - "borrow.errors.close",{mr: maintenanceRatio} + "borrow.errors.close", + {mr: maintenanceRatio} ); } @@ -608,7 +629,12 @@ class BorrowModalContent extends React.Component { let isPredictionMarket = this._isPredictionMarket(this.props); - let isOriginalBelowMCR = original_position.collateral > 0 && this._getCollateralRatio(original_position.debt, original_position.collateral) < maintenanceRatio; + let isOriginalBelowMCR = + original_position.collateral > 0 && + this._getCollateralRatio( + original_position.debt, + original_position.collateral + ) < maintenanceRatio; if (!isPredictionMarket && isNaN(feed_price)) { return ( @@ -661,12 +687,21 @@ class BorrowModalContent extends React.Component { /> )} - {isOriginalBelowMCR ? - - : null} + {isOriginalBelowMCR ? ( + + ) : null} {!isPredictionMarket ? ( -

    +
    :  @@ -755,7 +790,16 @@ class BorrowModalContent extends React.Component {
    - +
    - + { diff --git a/app/lib/workers/AddressIndexWorker.js b/app/lib/workers/AddressIndexWorker.js index fd6227d36d..3b77f7c58c 100644 --- a/app/lib/workers/AddressIndexWorker.js +++ b/app/lib/workers/AddressIndexWorker.js @@ -1,4 +1,4 @@ -import {key} from "bitsharesjs/es"; +import {key} from "bitsharesjs"; onmessage = function(event) { try { diff --git a/app/lib/workers/AesWorker.js b/app/lib/workers/AesWorker.js index e1a91136c0..824d5b48b0 100644 --- a/app/lib/workers/AesWorker.js +++ b/app/lib/workers/AesWorker.js @@ -1,5 +1,5 @@ require("babel-polyfill"); -import {Aes} from "bitsharesjs/es"; +import {Aes} from "bitsharesjs"; onmessage = function(event) { try { diff --git a/app/routerTransition.js b/app/routerTransition.js index 404f00cb2d..fe9f34211c 100644 --- a/app/routerTransition.js +++ b/app/routerTransition.js @@ -1,5 +1,5 @@ import {Apis, Manager, ChainConfig} from "bitsharesjs-ws"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import chainIds from "chain/chainIds"; // Stores diff --git a/app/stores/AccountRefsStore.js b/app/stores/AccountRefsStore.js index 172fda34b3..9b3f18bb61 100644 --- a/app/stores/AccountRefsStore.js +++ b/app/stores/AccountRefsStore.js @@ -2,7 +2,7 @@ import alt from "alt-instance"; import iDB from "idb-instance"; import Immutable from "immutable"; import BaseStore from "./BaseStore"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; import PrivateKeyStore from "stores/PrivateKeyStore"; import PrivateKeyActions from "actions/PrivateKeyActions"; diff --git a/app/stores/AccountStore.js b/app/stores/AccountStore.js index fb7f94ec00..cd69fe2caa 100644 --- a/app/stores/AccountStore.js +++ b/app/stores/AccountStore.js @@ -6,7 +6,7 @@ import SettingsActions from "actions/SettingsActions"; import WalletActions from "actions/WalletActions"; import iDB from "idb-instance"; import PrivateKeyStore from "./PrivateKeyStore"; -import {ChainStore, ChainValidation, FetchChain} from "bitsharesjs/es"; +import {ChainStore, ChainValidation, FetchChain} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; import AccountRefsStore from "stores/AccountRefsStore"; import AddressIndex from "stores/AddressIndex"; diff --git a/app/stores/AddressIndex.js b/app/stores/AddressIndex.js index 73ec64aa65..e32916225c 100644 --- a/app/stores/AddressIndex.js +++ b/app/stores/AddressIndex.js @@ -1,6 +1,6 @@ import alt from "alt-instance"; import iDB from "idb-instance"; -import {key} from "bitsharesjs/es"; +import {key} from "bitsharesjs"; import {ChainConfig} from "bitsharesjs-ws"; import Immutable from "immutable"; import BaseStore from "stores/BaseStore"; diff --git a/app/stores/BackupStore.js b/app/stores/BackupStore.js index 36ea0329c2..8483ee0c82 100644 --- a/app/stores/BackupStore.js +++ b/app/stores/BackupStore.js @@ -1,7 +1,7 @@ import alt from "alt-instance"; import BackupActions from "actions/BackupActions"; import BaseStore from "stores/BaseStore"; -import {hash, PublicKey} from "bitsharesjs/es"; +import {hash, PublicKey} from "bitsharesjs"; class BackupStore extends BaseStore { constructor() { diff --git a/app/stores/BalanceClaimActiveStore.js b/app/stores/BalanceClaimActiveStore.js index 799c0f94ad..6e1c762563 100644 --- a/app/stores/BalanceClaimActiveStore.js +++ b/app/stores/BalanceClaimActiveStore.js @@ -1,7 +1,7 @@ import alt from "alt-instance"; import Immutable from "immutable"; import BaseStore from "stores/BaseStore"; -import {key} from "bitsharesjs/es"; +import {key} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; import iDB from "idb-instance"; import BalanceClaimActiveActions from "actions/BalanceClaimActiveActions"; diff --git a/app/stores/BlockchainStore.js b/app/stores/BlockchainStore.js index bd646cb143..63bd9c0305 100644 --- a/app/stores/BlockchainStore.js +++ b/app/stores/BlockchainStore.js @@ -1,7 +1,7 @@ import Immutable from "immutable"; import alt from "alt-instance"; import BlockchainActions from "actions/BlockchainActions"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; // import {Block} from "./tcomb_structs"; class BlockchainStore { diff --git a/app/stores/BrainkeyStore.js b/app/stores/BrainkeyStore.js index 30f0bbe685..9ab3f05214 100644 --- a/app/stores/BrainkeyStore.js +++ b/app/stores/BrainkeyStore.js @@ -1,6 +1,6 @@ import alt from "alt-instance"; import Immutable from "immutable"; -import {ChainStore, key} from "bitsharesjs/es"; +import {ChainStore, key} from "bitsharesjs"; import BaseStore from "stores/BaseStore"; import BrainkeyActions from "actions/BrainkeyActions"; diff --git a/app/stores/MarketsStore.js b/app/stores/MarketsStore.js index 5571bdb24a..97a5b12049 100644 --- a/app/stores/MarketsStore.js +++ b/app/stores/MarketsStore.js @@ -3,7 +3,7 @@ import alt from "alt-instance"; import MarketsActions from "actions/MarketsActions"; import market_utils from "common/market_utils"; import ls from "common/localStorage"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import utils from "common/utils"; import { LimitOrder, diff --git a/app/stores/PrivateKeyStore.js b/app/stores/PrivateKeyStore.js index 9200bdfe10..69057d948e 100644 --- a/app/stores/PrivateKeyStore.js +++ b/app/stores/PrivateKeyStore.js @@ -8,7 +8,7 @@ import {PrivateKeyTcomb} from "./tcomb_structs"; import PrivateKeyActions from "actions/PrivateKeyActions"; import CachedPropertyActions from "actions/CachedPropertyActions"; import AddressIndex from "stores/AddressIndex"; -import {PublicKey, ChainStore, Aes} from "bitsharesjs/es"; +import {PublicKey, ChainStore, Aes} from "bitsharesjs"; /** No need to wait on the promises returned by this store as long as this.state.privateKeyStorage_error == false and diff --git a/app/stores/WalletDb.js b/app/stores/WalletDb.js index 4ba028eba2..1920b04fdd 100644 --- a/app/stores/WalletDb.js +++ b/app/stores/WalletDb.js @@ -12,7 +12,7 @@ import TransactionConfirmActions from "actions/TransactionConfirmActions"; import WalletUnlockActions from "actions/WalletUnlockActions"; import PrivateKeyActions from "actions/PrivateKeyActions"; import AccountActions from "actions/AccountActions"; -import {ChainStore, PrivateKey, key, Aes} from "bitsharesjs/es"; +import {ChainStore, PrivateKey, key, Aes} from "bitsharesjs"; import {Apis, ChainConfig} from "bitsharesjs-ws"; import AddressIndex from "stores/AddressIndex"; import SettingsActions from "actions/SettingsActions"; diff --git a/app/stores/WalletManagerStore.js b/app/stores/WalletManagerStore.js index 92973a8691..f26e6dae91 100644 --- a/app/stores/WalletManagerStore.js +++ b/app/stores/WalletManagerStore.js @@ -6,7 +6,7 @@ import BalanceClaimActiveStore from "stores/BalanceClaimActiveStore"; import CachedPropertyStore from "stores/CachedPropertyStore"; import PrivateKeyActions from "actions/PrivateKeyActions"; import WalletActions from "actions/WalletActions"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import BaseStore from "stores/BaseStore"; import iDB from "idb-instance"; import Immutable from "immutable"; diff --git a/package-lock.json b/package-lock.json index cf7486a3ee..d17f17e48f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -165,9 +165,9 @@ } }, "globals": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz", - "integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==", + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", "dev": true } } @@ -778,17 +778,6 @@ "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", "dev": true }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "dev": true, - "optional": true, - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, "app-builder-bin": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-1.9.5.tgz", @@ -1054,29 +1043,6 @@ "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", "dev": true }, - "babel-cli": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", - "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-polyfill": "^6.26.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "chokidar": "^1.6.1", - "commander": "^2.11.0", - "convert-source-map": "^1.5.0", - "fs-readdir-recursive": "^1.0.0", - "glob": "^7.1.2", - "lodash": "^4.17.4", - "output-file-sync": "^1.1.2", - "path-is-absolute": "^1.0.1", - "slash": "^1.0.0", - "source-map": "^0.5.6", - "v8flags": "^2.1.1" - } - }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -1116,9 +1082,9 @@ } }, "babel-eslint": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.3.tgz", - "integrity": "sha512-0HeSTtaXg/Em7FCUWxwOT+KeFSO1O7LuRuzhk7g+1BjwdlQGlHq4OyMi3GqGxrNfEq8jEi6Hmt5ylEQUhurgiQ==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.5.tgz", + "integrity": "sha512-TcdEGCHHquOPQOlH6Fe6MLwPWWWJLdeKhcGoLfOTShETpoH8XYWhjWJw38KCKaTca7c/EdxLolnbakixKxnXDg==", "dev": true, "requires": { "@babel/code-frame": "7.0.0-beta.44", @@ -1365,9 +1331,9 @@ } }, "babel-loader": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz", - "integrity": "sha512-/hbyEvPzBJuGpk9o80R0ZyTej6heEOr59GoEUtn8qFKbnx4cJm9FWES6J/iv644sYgrtVw9JJQkjaLW/bqb5gw==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz", + "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==", "dev": true, "requires": { "find-cache-dir": "^1.0.0", @@ -1970,9 +1936,9 @@ }, "dependencies": { "core-js": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", - "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==", + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", "dev": true }, "regenerator-runtime": { @@ -3188,43 +3154,6 @@ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "dev": true }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, "chownr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", @@ -8288,12 +8217,6 @@ } } }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true - }, "fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -13224,9 +13147,9 @@ } }, "moment": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz", - "integrity": "sha512-shJkRTSebXvsVqk56I+lkb2latjBs8I+pc2TzWc545y2iFnSjm7Wg0QMh+ZWcdSLQyGEau5jI8ocnmkyTgr9YQ==" + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" }, "moment-timezone": { "version": "0.5.17", @@ -14078,17 +14001,6 @@ "os-tmpdir": "^1.0.0" } }, - "output-file-sync": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", - "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.4", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.0" - } - }, "p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", @@ -19612,12 +19524,6 @@ } } }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -19680,15 +19586,6 @@ "integrity": "sha512-qNdTUMaCjPs4eEnM3W9H94R3sU70YCuT+/ST7nUf+id1bVOrdjrpUaeZLqPBPRph3hsgn4a4BvwpxhHZx+oSDg==", "dev": true }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", - "dev": true, - "requires": { - "user-home": "^1.1.1" - } - }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", diff --git a/package.json b/package.json index 6ff2b87147..7d637d65b9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ }, "main": "build/electron/index.js", "scripts": { - "test:market": "cross-env NODE_ENV=test mocha --compilers js:babel-core/register ./app/test/marketTests --watch", + "test:market": "cross-env NODE_ENV=test mocha --require babel-core/register --watch --watch-extensions js ./app/test/marketTests", "bench:market": "cross-env NODE_ENV=test babel ./lib/common/MarketClasses.js -o ./app/test/MarketClasses.js && cross-env NODE_ENV=test node --harmony ./test/marketBenchmark", "profile-dev": "webpack --env.dev --env.profile --profile --json > stats-dev.json", "profile-build": "cross-env NODE_ENV=production webpack --env.prod --env.profile --env.hash --env.baseUrl='' --profile --json > stats-prod.json", @@ -153,7 +153,7 @@ "js-sha256": "^0.2.3", "lodash-es": "^4.17.10", "lzma": "2.1.6", - "moment": "^2.20.1", + "moment": "^2.22.2", "moment-timezone": "^0.5.16", "node-rsa": "^0.4.2", "notifyjs": "^3.0.0", @@ -190,10 +190,10 @@ "zxcvbn-async": "0.0.5" }, "devDependencies": { - "babel-cli": "^6.26.0", - "babel-eslint": "^8.2.2", + "babel-core": "^6.26.3", + "babel-eslint": "^8.2.5", "babel-jest": "^18.0.0", - "babel-loader": "^7.1.4", + "babel-loader": "^7.1.5", "babel-plugin-lodash": "^3.3.2", "babel-plugin-webpack-alias": "^2.1.2", "babel-polyfill": "^6.26.0", diff --git a/webpack.config.js b/webpack.config.js index 7c33243956..9295c46d93 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -359,7 +359,18 @@ module.exports = function(env) { path.resolve(root_dir, "app/lib"), "node_modules" ], - extensions: [".js", ".jsx", ".coffee", ".json"] + extensions: [".js", ".jsx", ".coffee", ".json"], + mainFields: ["module", "jsnext:main", "browser", "main"], + alias: { + moment$: path.resolve( + root_dir, + "node_modules/moment/moment.js" + ), + "bitshares-ui-style-guide$": path.resolve( + root_dir, + "node_modules/bitshares-ui-style-guide/dist/main.js" + ) + } }, plugins: plugins }; From ea94d9d9d9ff301a269ace4c9df8f5026164dc54 Mon Sep 17 00:00:00 2001 From: svk Date: Thu, 12 Jul 2018 13:04:00 +0200 Subject: [PATCH 13/69] Fix #1638: Use new fill_price field for more precise market history (#1691) * #1638: Add FillPrice class with tests * #1638: Refactor market histories using FillPrice class * #1638: Remove unused parse_order_history --- .../stylesheets/components/_exchange.scss | 4 + app/components/Exchange/Exchange.jsx | 63 +--- app/components/Exchange/ExchangeHeader.jsx | 2 +- app/components/Exchange/MarketHistory.jsx | 108 +++--- app/components/Exchange/MyOpenOrders.jsx | 2 +- app/components/Exchange/OrderBook.jsx | 15 +- app/components/Utility/PriceText.jsx | 6 +- app/lib/common/MarketClasses.js | 113 +++++- app/lib/common/market_utils.js | 73 ---- app/stores/MarketsStore.js | 14 +- app/test/marketTests.js | 330 +++++++++++++++++- 11 files changed, 519 insertions(+), 211 deletions(-) diff --git a/app/assets/stylesheets/components/_exchange.scss b/app/assets/stylesheets/components/_exchange.scss index bd444cc0ae..d8900a5ee9 100644 --- a/app/assets/stylesheets/components/_exchange.scss +++ b/app/assets/stylesheets/components/_exchange.scss @@ -1,3 +1,7 @@ +div#CenterContent { + padding-bottom: 2rem !important; +} + .market-layout { > .grid-block { // padding: 0.25rem 0.25rem 0.25rem 0.25rem !important; diff --git a/app/components/Exchange/Exchange.jsx b/app/components/Exchange/Exchange.jsx index bd724eb7e0..c3b5ecf204 100644 --- a/app/components/Exchange/Exchange.jsx +++ b/app/components/Exchange/Exchange.jsx @@ -1239,7 +1239,7 @@ class Exchange extends React.Component { quoteSymbol, baseSymbol, showCallLimit = false, - latestPrice, + latest, changeClass; const showVolumeChart = this.props.viewSettings.get( @@ -1282,56 +1282,16 @@ class Exchange extends React.Component { // Latest price if (activeMarketHistory.size) { - // Orders come in pairs, first is driver. Third entry is first of second pair. - let latest_two = activeMarketHistory.take(3); - let latest = latest_two.first(); + let latest_two = activeMarketHistory.take(2); + latest = latest_two.first(); let second_latest = latest_two.last(); - let paysAsset, - receivesAsset, - isAsk = false; - if (latest.pays.asset_id === base.get("id")) { - paysAsset = base; - receivesAsset = quote; - isAsk = true; - } else { - paysAsset = quote; - receivesAsset = base; - } - let flipped = - base.get("id").split(".")[2] > quote.get("id").split(".")[2]; - latestPrice = market_utils.parse_order_history( - latest, - paysAsset, - receivesAsset, - isAsk, - flipped - ); - - isAsk = false; - if (second_latest) { - if (second_latest.pays.asset_id === base.get("id")) { - paysAsset = base; - receivesAsset = quote; - isAsk = true; - } else { - paysAsset = quote; - receivesAsset = base; - } - let oldPrice = market_utils.parse_order_history( - second_latest, - paysAsset, - receivesAsset, - isAsk, - flipped - ); - changeClass = - latestPrice.full === oldPrice.full - ? "" - : latestPrice.full - oldPrice.full > 0 - ? "change-up" - : "change-down"; - } + changeClass = + latest.getPrice() === second_latest.getPrice() + ? "" + : latest.getPrice() - second_latest.getPrice() > 0 + ? "change-up" + : "change-down"; } // Fees @@ -1552,7 +1512,7 @@ class Exchange extends React.Component { let orderBook = ( {!leftOrderBook ? orderBook : null} diff --git a/app/components/Exchange/ExchangeHeader.jsx b/app/components/Exchange/ExchangeHeader.jsx index 2b85ce9ab4..68f56ab06a 100644 --- a/app/components/Exchange/ExchangeHeader.jsx +++ b/app/components/Exchange/ExchangeHeader.jsx @@ -284,7 +284,7 @@ export default class ExchangeHeader extends React.Component { quote.get("id").split(".")[2]; historyRows = myHistory .filter(a => { let opType = a.getIn(["op", 0]); @@ -102,38 +110,26 @@ class MarketHistory extends React.Component { return b.get("block_num") - a.get("block_num"); }) .map(trx => { - let order = trx.toJS().op[1]; - keyIndex++; - let paysAsset, - receivesAsset, - isAsk = false; - if (order.pays.asset_id === base.get("id")) { - paysAsset = base; - receivesAsset = quote; - isAsk = true; - } else { - paysAsset = quote; - receivesAsset = base; - } - - let parsed_order = market_utils.parse_order_history( - order, - paysAsset, - receivesAsset, - isAsk, - flipped + let fill = new FillOrder( + trx.toJS(), + assets, + quote.get("id") ); - const block_num = trx.get("block_num"); + return ( - - - + + + - {parsed_order.receives} - {parsed_order.pays} + {fill.amountToReceive()} + {fill.amountToPay()} @@ -141,48 +137,22 @@ class MarketHistory extends React.Component { }) .toArray(); } else if (history && history.size) { - let index = 0; - let keyIndex = -1; - let flipped = - base.get("id").split(".")[2] > quote.get("id").split(".")[2]; historyRows = this.props.history - .filter(() => { - index++; - return index % 2 === 0; - }) .take(100) - .map(order => { - keyIndex++; - let paysAsset, - receivesAsset, - isAsk = false; - if (order.pays.asset_id === base.get("id")) { - paysAsset = base; - receivesAsset = quote; - isAsk = true; - } else { - paysAsset = quote; - receivesAsset = base; - } - let parsed_order = market_utils.parse_order_history( - order, - paysAsset, - receivesAsset, - isAsk, - flipped - ); + .map(fill => { return ( - - - + + + - {parsed_order.receives} - {parsed_order.pays} - - {counterpart.localize(new Date(order.time), { + {fill.amountToReceive()} + {fill.amountToPay()} + + {counterpart.localize(fill.time, { type: "date", format: getLocale() @@ -206,7 +176,7 @@ class MarketHistory extends React.Component {
    diff --git a/app/components/Utility/PriceText.jsx b/app/components/Utility/PriceText.jsx index 2adaef7d21..bf04500c30 100644 --- a/app/components/Utility/PriceText.jsx +++ b/app/components/Utility/PriceText.jsx @@ -3,9 +3,9 @@ import utils from "common/utils"; class PriceText extends React.Component { render() { - let {price, preFormattedPrice, quote, base, component} = this.props; - - let formattedPrice = preFormattedPrice + let {price, preFormattedPrice, quote, base} = this.props; + if (!price && !preFormattedPrice) return null; + let formattedPrice = !!preFormattedPrice ? preFormattedPrice : utils.price_to_text(price, quote, base); diff --git a/app/lib/common/MarketClasses.js b/app/lib/common/MarketClasses.js index c14402240e..fad7298a9c 100644 --- a/app/lib/common/MarketClasses.js +++ b/app/lib/common/MarketClasses.js @@ -1032,6 +1032,116 @@ class GroupedOrder { } } +class FillOrder { + constructor(fill, assets, market_base) { + /* Check if the fill op is from a user history object */ + if ("virtual_op" in fill) { + fill = { + id: fill.id, + op: fill.op[1], + time: null, + block: fill.block_num + }; + } + if (!market_base) { + throw new Error("LimitOrder requires a market_base id"); + } + this.op = fill.op; + this.assets = assets; + this.market_base = market_base; + this.id = fill.id; + this.order_id = fill.op.order_id; + this.isCall = utils.is_object_type(fill.op.order_id, "call_order") + ? true + : false; + + this.isBid = fill.op.receives.asset_id === this.market_base; + this.className = this.isCall + ? "orderHistoryCall" + : this.isBid + ? "orderHistoryBid" + : "orderHistoryAsk"; + this.time = fill.time && new Date(utils.makeISODateString(fill.time)); + this.block = fill.block; + this.account = fill.op.account || fill.op.account_id; + + this.is_maker = fill.op.is_maker; + + let pays = new Asset({ + asset_id: fill.op.pays.asset_id, + amount: parseInt(fill.op.pays.amount, 10), + precision: assets[fill.op.pays.asset_id].precision + }); + let receives = new Asset({ + asset_id: fill.op.receives.asset_id, + amount: parseInt(fill.op.receives.amount, 10), + precision: assets[fill.op.receives.asset_id].precision + }); + + this.pays = this.isBid ? pays : receives; + this.receives = this.isBid ? receives : pays; + + if (fill.op.fill_price) { + this.fill_price = new Price({ + base: new Asset({ + asset_id: fill.op.fill_price.base.asset_id, + amount: parseInt(fill.op.fill_price.base.amount, 10), + precision: + assets[fill.op.fill_price.base.asset_id].precision + }), + quote: new Asset({ + asset_id: fill.op.fill_price.quote.asset_id, + amount: parseInt(fill.op.fill_price.quote.amount, 10), + precision: + assets[fill.op.fill_price.quote.asset_id].precision + }) + }); + } + + this.fee = new Asset({ + asset_id: fill.op.fee.asset_id, + amount: parseInt(fill.op.fee.amount, 10), + precision: assets[fill.op.fee.asset_id].precision + }); + } + + _calculatePrice() { + if (this._cached_price) { + return this._cached_price; + } else { + return (this._cached_price = new Price({ + base: this.pays, + quote: this.receives + }).toReal(false)); + } + } + + getPrice() { + if (this.fill_price) { + return this.fill_price.toReal( + this.fill_price.base.asset_id === this.receives.asset_id + ); + } else { + return this._calculatePrice(); + } + } + + amountToReceive() { + let amount = this.fill_price + ? this.pays.times(this.fill_price).getAmount({real: true}) + : this.receives.getAmount({real: true}); + + return utils.format_number(amount, this.receives.precision); + } + + amountToPay() { + return utils.format_number( + this.pays.getAmount({real: true}), + this.pays.precision + ); + } +} + export { Asset, Price, @@ -1043,5 +1153,6 @@ export { CallOrder, SettleOrder, didOrdersChange, - GroupedOrder + GroupedOrder, + FillOrder }; diff --git a/app/lib/common/market_utils.js b/app/lib/common/market_utils.js index 4a58aedf95..f94169e9d7 100644 --- a/app/lib/common/market_utils.js +++ b/app/lib/common/market_utils.js @@ -300,79 +300,6 @@ const MarketUtils = { }; }, - parse_order_history(order, paysAsset, receivesAsset, isAsk, flipped) { - let isCall = - order.order_id.split(".")[1] == object_type.limit_order - ? false - : true; - let receivePrecision = utils.get_asset_precision( - receivesAsset.get("precision") - ); - let payPrecision = utils.get_asset_precision( - paysAsset.get("precision") - ); - - let receives = order.receives.amount / receivePrecision; - receives = utils.format_number( - receives, - receivesAsset.get("precision") - ); - let pays = order.pays.amount / payPrecision; - pays = utils.format_number(pays, paysAsset.get("precision")); - let price_full = utils.get_asset_price( - order.receives.amount, - receivesAsset, - order.pays.amount, - paysAsset, - isAsk - ); - // price_full = !flipped ? (1 / price_full) : price_full; - // let {int, dec} = this.split_price(price_full, isAsk ? receivesAsset.get("precision") : paysAsset.get("precision")); - - let {int, dec, trailing} = utils.price_to_text( - price_full, - isAsk ? receivesAsset : paysAsset, - isAsk ? paysAsset : receivesAsset - ); - let className = isCall - ? "orderHistoryCall" - : isAsk - ? "orderHistoryBid" - : "orderHistoryAsk"; - - let time; - if (order.time) { - time = order.time.split("T")[1]; - let now = new Date(); - let offset = now.getTimezoneOffset() / 60; - let date = utils.format_date(order.time).split(/\W/); - let hour = time.substr(0, 2); - let hourNumber = parseInt(hour, 10); - let localHour = hourNumber - offset; - if (localHour >= 24) { - localHour -= 24; - } else if (localHour < 0) { - localHour += 24; - } - let hourString = localHour.toString(); - if (parseInt(hourString, 10) < 10) { - hourString = "0" + hourString; - } - time = - date[0] + "/" + date[1] + " " + time.replace(hour, hourString); - } - return { - receives: isAsk ? receives : pays, - pays: isAsk ? pays : receives, - full: price_full, - int: int, - dec: dec, - trailing: trailing, - className: className, - time: time - }; - }, - split_price(price, pricePrecision) { // We need to figure out a better way to set the number of decimals let price_split = utils diff --git a/app/stores/MarketsStore.js b/app/stores/MarketsStore.js index 97a5b12049..f65504a5ff 100644 --- a/app/stores/MarketsStore.js +++ b/app/stores/MarketsStore.js @@ -13,7 +13,8 @@ import { Asset, didOrdersChange, Price, - GroupedOrder + GroupedOrder, + FillOrder } from "common/MarketClasses"; // import { @@ -406,19 +407,16 @@ class MarketsStore { if (result.history) { this.activeMarketHistory = this.activeMarketHistory.clear(); result.history.forEach(order => { - if (!/Z$/.test(order.time)) { - order.time += "Z"; - } - order.op.time = order.time; /* Only include history objects that aren't 'something for nothing' to avoid confusion */ if ( + !order.op.is_maker && !( order.op.receives.amount == 0 || order.op.pays.amount == 0 ) ) { this.activeMarketHistory = this.activeMarketHistory.add( - order.op + new FillOrder(order, assets, this.quoteAsset.get("id")) ); } }); @@ -426,9 +424,9 @@ class MarketsStore { if (result.fillOrders) { result.fillOrders.forEach(fill => { - // console.log("fill:", fill); + console.log("fill:", fill, JSON.stringify(fill)); this.activeMarketHistory = this.activeMarketHistory.add( - fill[0][1] + new FillOrder(fill[0][1], assets, this.quoteAsset.get("id")) ); }); } diff --git a/app/test/marketTests.js b/app/test/marketTests.js index 2cd16d1176..05c5cf918c 100644 --- a/app/test/marketTests.js +++ b/app/test/marketTests.js @@ -7,7 +7,8 @@ import { precisionToRatio, LimitOrder, SettleOrder, - CallOrder + CallOrder, + FillOrder } from "../lib/common/MarketClasses"; import assert from "assert"; @@ -15,7 +16,13 @@ console.log("**** Starting market tests here ****"); const asset1 = {asset_id: "1.3.0", precision: 5}; const asset2 = {asset_id: "1.3.121", precision: 4}; // bitUSD const asset3 = {asset_id: "1.3.113", precision: 4}; // bitCNY -const assets = {"1.3.0": asset1, "1.3.121": asset2, "1.3.113": asset3}; +const asset4 = {asset_id: "1.3.22", precision: 4}; // PEG.FAKEUSD +const assets = { + "1.3.0": asset1, + "1.3.121": asset2, + "1.3.113": asset3, + "1.3.22": asset4 +}; describe("Utility functions", function() { describe("limitByPrecision", function() { @@ -1318,3 +1325,322 @@ describe("Settle Order", function() { assert.equal(order2.isBid(), true, "Order is a bid"); }); }); + +describe("Fill Order", function() { + const fill_1 = { + id: "5.0.46863942", + key: { + base: "1.3.0", + quote: "1.3.121", + sequence: -6204499 + }, + op: { + account_id: "1.2.438680", + fee: { + amount: 0, + asset_id: "1.3.121" + }, + fill_price: { + base: { + amount: 42848745, + asset_id: "1.3.0" + }, + quote: { + amount: 626498, + asset_id: "1.3.121" + } + }, + is_maker: true, + order_id: "1.7.104920573", + pays: { + amount: 55674, + asset_id: "1.3.0" + }, + receives: { + amount: 814, + asset_id: "1.3.121" + } + }, + time: "2018-07-11T07:48:42" + }; + + const fill_2 = { + id: "5.0.46863942", + key: { + base: "1.3.0", + quote: "1.3.121", + sequence: -6204499 + }, + op: { + account_id: "1.2.438680", + fee: { + amount: 0, + asset_id: "1.3.121" + }, + fill_price: { + base: { + amount: 42848745, + asset_id: "1.3.0" + }, + quote: { + amount: 626498, + asset_id: "1.3.121" + } + }, + is_maker: true, + order_id: "1.7.104920573", + pays: { + amount: 55674, + asset_id: "1.3.121" + }, + receives: { + amount: 814, + asset_id: "1.3.0" + } + }, + time: "2018-07-11T07:48:42" + }; + + const fill_3 = { + id: "5.0.46863942", + key: { + base: "1.3.0", + quote: "1.3.121", + sequence: -6204499 + }, + op: { + account_id: "1.2.438680", + fee: { + amount: 0, + asset_id: "1.3.121" + }, + fill_price: { + base: { + amount: 42848745, + asset_id: "1.3.0" + }, + quote: { + amount: 626498, + asset_id: "1.3.121" + } + }, + is_maker: true, + order_id: "1.8.104920573", + pays: { + amount: 55674, + asset_id: "1.3.121" + }, + receives: { + amount: 814, + asset_id: "1.3.0" + } + }, + time: "2018-07-11T07:48:42" + }; + + const myHistorySellMarketBase = "1.3.22"; + const myHistorySellTaker = { + block_num: 18884610, + id: "1.11.37874337", + op: [ + 4, + { + account_id: "1.2.680", + fee: { + amount: 0, + asset_id: "1.3.0" + }, + fill_price: { + base: { + amount: 1000200002, + asset_id: "1.3.0" + }, + quote: { + amount: 20000, + asset_id: "1.3.22" + } + }, + is_maker: false, + order_id: "1.7.74696", + pays: { + amount: 10000, + asset_id: "1.3.22" + }, + receives: { + amount: 500100001, + asset_id: "1.3.0" + } + } + ], + op_in_trx: 0, + result: [0, {}], + trx_in_block: 0, + virtual_op: 29010 + }; + const myHistorySellMaker = { + block_num: 18885060, + id: "1.11.37874356", + op: [ + 4, + { + account_id: "1.2.680", + fee: { + amount: 0, + asset_id: "1.3.0" + }, + fill_price: { + base: { + amount: 20000, + asset_id: "1.3.22" + }, + quote: { + amount: 1020000000, + asset_id: "1.3.0" + } + }, + is_maker: true, + order_id: "1.7.74697", + pays: { + amount: 20000, + asset_id: "1.3.22" + }, + receives: { + amount: 1020000000, + asset_id: "1.3.0" + } + } + ], + op_in_trx: 0, + result: [0, {}], + trx_in_block: 0, + virtual_op: 29043 + }; + + const marketHistorySell = { + id: "5.0.44514", + key: { + base: "1.3.0", + quote: "1.3.22", + sequence: -40474 + }, + op: { + account_id: "1.2.680", + fee: { + amount: 0, + asset_id: "1.3.0" + }, + fill_price: { + base: { + amount: 1000200002, + asset_id: "1.3.0" + }, + quote: { + amount: 20000, + asset_id: "1.3.22" + } + }, + is_maker: false, + order_id: "1.7.74696", + pays: { + amount: 10000, + asset_id: "1.3.22" + }, + receives: { + amount: 500100001, + asset_id: "1.3.0" + } + }, + time: "2018-07-12T09:18:57" + }; + + const marketHistorySell2 = { + id: "5.0.40990", + key: { + base: "1.3.0", + quote: "1.3.22", + sequence: -40429 + }, + op: { + account_id: "1.2.780", + fee: { + amount: 0, + asset_id: "1.3.0" + }, + fill_price: { + base: { + amount: 130, + asset_id: "1.3.22" + }, + quote: { + amount: 272073, + asset_id: "1.3.0" + } + }, + is_maker: false, + order_id: "1.4.32", + pays: { + amount: 10000, + asset_id: "1.3.22" + }, + receives: { + amount: 20928691, + asset_id: "1.3.0" + } + }, + time: "2017-02-10T09:07:50" + }; + + it("Instantiates", function() { + new FillOrder(fill_1, assets, "1.3.0"); + }); + + it("Returns the correct price", function() { + let o6 = new FillOrder(marketHistorySell2, assets, "1.3.22"); + assert.equal(o6.getPrice(), 209.28692308); + + let o3 = new FillOrder(marketHistorySell, assets, "1.3.22"); + assert.equal(o3.getPrice(), 5001.00001); + + let o4 = new FillOrder(myHistorySellMaker, assets, "1.3.22"); + assert.equal(o4.getPrice(), 5100); + + let o5 = new FillOrder(myHistorySellTaker, assets, "1.3.22"); + assert.equal(o5.getPrice(), 5001.00001); + + let o = new FillOrder(fill_1, assets, "1.3.0"); + let o2 = new FillOrder(fill_1, assets, "1.3.121"); + + assert.equal(o.getPrice(), 0.14621152); + assert.equal(o2.getPrice(), 6.83940651); + assert(o.getPrice() !== o._calculatePrice()); + }); + + it("Returns the amount to receive", function() { + let o = new FillOrder(fill_1, assets, "1.3.0"); + assert.equal(o.amountToReceive(), 0.55672); + }); + + it("Returns the amount to pay", function() { + let o = new FillOrder(fill_1, assets, "1.3.0"); + assert.equal(o.amountToPay(), 0.0814); + }); + + it("Can tell what type of fill it was", function() { + let o4 = new FillOrder(myHistorySellTaker, assets, "1.3.22"); + assert.equal(o4.isBid, false); + + let o6 = new FillOrder(myHistorySellMaker, assets, "1.3.22"); + assert.equal(o6.isBid, false); + + let o5 = new FillOrder(marketHistorySell, assets, "1.3.22"); + assert.equal(o5.isBid, false); + + let o = new FillOrder(fill_1, assets, "1.3.0"); + assert.equal(o.isBid, false); + let o2 = new FillOrder(fill_2, assets, "1.3.0"); + assert.equal(o2.isBid, true); + let o3 = new FillOrder(fill_3, assets, "1.3.0"); + assert.equal(o3.isBid, true); + assert.equal(o3.isCall, true); + }); +}); From 18910df9352114e4e2586b26a885d2d10fdd711a Mon Sep 17 00:00:00 2001 From: svk Date: Fri, 13 Jul 2018 14:08:33 +0200 Subject: [PATCH 14/69] #1642: Group market quotes and enable user configuration (#1694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #1642: Enable groupîng all gateway assets for a given asset in one market list * Fix #1642: Add a modal for market quote asset configuration --- app/actions/SettingsActions.js | 4 + app/assets/locales/locale-de.json | 7 + app/assets/locales/locale-en.json | 7 + app/assets/locales/locale-es.json | 7 + app/assets/locales/locale-fr.json | 7 + app/assets/locales/locale-it.json | 7 + app/assets/locales/locale-ja.json | 7 + app/assets/locales/locale-ko.json | 7 + app/assets/locales/locale-ru.json | 7 + app/assets/locales/locale-tr.json | 7 + app/assets/locales/locale-zh.json | 7 + app/branding.js | 2 +- app/components/Exchange/MyMarkets.jsx | 390 ++++++++++++------ .../Exchange/QuoteSelectionModal.jsx | 179 ++++++++ app/components/Icon/icon.scss | 76 ++-- app/components/Utility/AssetSelector.jsx | 2 +- app/stores/SettingsStore.js | 81 +++- 17 files changed, 625 insertions(+), 179 deletions(-) create mode 100644 app/components/Exchange/QuoteSelectionModal.jsx diff --git a/app/actions/SettingsActions.js b/app/actions/SettingsActions.js index f1bfe02e4e..c86a7ade4d 100644 --- a/app/actions/SettingsActions.js +++ b/app/actions/SettingsActions.js @@ -72,6 +72,10 @@ class SettingsActions { setExchangeTutorialShown(value) { return value; } + + modifyPreferedBases(payload) { + return payload; + } } export default alt.createActions(SettingsActions); diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index e205ff58d7..91bc70b569 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -485,6 +485,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Asks", "atr": "Average True Range", "balance": "Guthaben", @@ -511,6 +512,7 @@ "confirm_sell": "Your order is %(diff)s times lower than the highest bid, are you sure?", "core_rate": "Gebührenrate", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Exponential Moving Average", @@ -547,6 +549,8 @@ "use": "Use" }, "more": "Alle Märkte", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "Meine Asks", "my_bids": "Meine Bids", "my_history": "Meine Historie", @@ -568,8 +572,10 @@ "price_market": "Market Price", "quantity": "Quantität", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "Quote Verfügbarkeit", "receive": "Empfangen", + "remove": "Remove", "rsi": "Relative Strength Index", "search": "Search for more markets here", "sell": "Verkaufen", @@ -581,6 +587,7 @@ "short": "Short", "show_asks": "Show all asks", "show_bids": "Show all bids", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Simple Moving Average", "spread": "Spread", diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 5167dfa7af..aea0f56d24 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -481,6 +481,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Sell orders", "atr": "Average True Range", "balance": "Balance", @@ -507,6 +508,7 @@ "confirm_sell": "Your order is %(diff)s times lower than the highest bid, are you sure?", "core_rate": "Fee Rate", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Exponential Moving Average", @@ -543,6 +545,8 @@ "use": "Use" }, "more": "Find markets", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "My asks", "my_bids": "My bids", "my_history": "My trades", @@ -564,8 +568,10 @@ "price_market": "Market Price", "quantity": "Quantity", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "Quote supply", "receive": "Receive", + "remove": "Remove", "rsi": "Relative Strength Index", "search": "Search for more markets here", "sell": "Sell", @@ -577,6 +583,7 @@ "short": "Short", "show_asks": "Show all asks", "show_bids": "Show all bids", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Simple Moving Average", "spread": "Spread", diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index 4d652dc9fd..d9dd29c0c3 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -493,6 +493,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Vender ordenes", "atr": "Average True Range", "balance": "Su balance", @@ -519,6 +520,7 @@ "confirm_sell": "Tu pedido es %(diff)s veces inferior a la oferta más alta, ¿estás seguro?", "core_rate": "Tasa de Comisión", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Exponential Moving Average", @@ -555,6 +557,8 @@ "use": "Use" }, "more": "busca mercados", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "Mis domandas", "my_bids": "Mis ofertas", "my_history": "Mis comercios", @@ -576,8 +580,10 @@ "price_market": "Market Price", "quantity": "Monto", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "Fuente de cotización", "receive": "Recibir", + "remove": "Remove", "rsi": "Relative Strength Index", "search": "Busque más mercados aquí", "sell": "Vender", @@ -589,6 +595,7 @@ "short": "Corto", "show_asks": "Mostrar todas las domandas", "show_bids": "Mostrar todas las ofertas", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Simple Moving Average", "spread": "Margen (spread)", diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index e05c527f67..ebb4bf14b5 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -481,6 +481,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Sell orders", "atr": "Average True Range", "balance": "Solde", @@ -507,6 +508,7 @@ "confirm_sell": "Your order is %(diff)s times lower than the highest bid, are you sure?", "core_rate": "Fee Rate", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Exponential Moving Average", @@ -543,6 +545,8 @@ "use": "Use" }, "more": "Find markets", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "My asks", "my_bids": "My bids", "my_history": "My trades", @@ -564,8 +568,10 @@ "price_market": "Market Price", "quantity": "Quantité", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "Quote supply", "receive": "Receive", + "remove": "Remove", "rsi": "Relative Strength Index", "search": "Search for more markets here", "sell": "Vendre", @@ -577,6 +583,7 @@ "short": "Short", "show_asks": "Show all asks", "show_bids": "Show all bids", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Simple Moving Average", "spread": "Spread", diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index 59a0785bae..083d9400a4 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -491,6 +491,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Ordini di vendita", "atr": "Average True Range", "balance": "Saldo", @@ -517,6 +518,7 @@ "confirm_sell": "Il tuo ordine è %(diff)s volte più basso della domanda più alta, sei sicuro?", "core_rate": "Tasso di commissione", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Exponential Moving Average", @@ -553,6 +555,8 @@ "use": "Use" }, "more": "Trova mercati", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "Le mie ask", "my_bids": "Le mie bid", "my_history": "Il mio storico transazioni", @@ -574,8 +578,10 @@ "price_market": "Market Price", "quantity": "Quantità", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "Disponibilità valuta quotata", "receive": "Ricevi", + "remove": "Remove", "rsi": "Relative Strength Index", "search": "Cerca qui altri mercati", "sell": "Vendi", @@ -587,6 +593,7 @@ "short": "Short", "show_asks": "Mostra tutte le ask", "show_bids": "Mostra tutte le bid", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Simple Moving Average", "spread": "Spread", diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index 468ba89e11..24c62b0899 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -481,6 +481,7 @@ "top_markets": "トップマーケット" }, "exchange": { + "add_quote": "Add", "asks": "売り注文", "atr": "アベレージトゥルーレンジ", "balance": "残高", @@ -507,6 +508,7 @@ "confirm_sell": "あなたの注文は、最高ビッド価格より%(diff)s倍低いです。続行してもよろしいですか?", "core_rate": "手数料率", + "custom_quote": "Add a custom quote", "deposit": "入金", "description": "説明", "ema": "指数平滑移動平均", @@ -543,6 +545,8 @@ "use": "Use" }, "more": "マーケットを探す", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "自分の売り注文", "my_bids": "自分の買い注文", "my_history": "自分の履歴", @@ -564,8 +568,10 @@ "price_market": "マーケット価格", "quantity": "数量", "quote": "クオート通貨:", + "quote_selection": "Modify quote selection", "quote_supply": "クオート供給量", "receive": "取得", + "remove": "Remove", "rsi": "相対力指数", "search": "他のマーケットを検索する", "sell": "売る", @@ -577,6 +583,7 @@ "short": "ショート", "show_asks": "すべての売り注文を見る", "show_bids": "すべての買い注文を見る", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "{star_icon}のみ表示", "sma": "単純移動平均", "spread": "スプレッド", diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index 1b78a4e604..df6d1fa271 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -481,6 +481,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Sell orders", "atr": "Average True Range", "balance": "잔고", @@ -507,6 +508,7 @@ "confirm_sell": "Your order is %(diff)s times lower than the highest bid, are you sure?", "core_rate": "Fee Rate", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Exponential Moving Average", @@ -543,6 +545,8 @@ "use": "Use" }, "more": "Find markets", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "My asks", "my_bids": "My bids", "my_history": "My trades", @@ -564,8 +568,10 @@ "price_market": "Market Price", "quantity": "총량", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "유통량", "receive": "Receive", + "remove": "Remove", "rsi": "Relative Strength Index", "search": "Search for more markets here", "sell": "매도", @@ -577,6 +583,7 @@ "short": "Short", "show_asks": "Show all asks", "show_bids": "Show all bids", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Simple Moving Average", "spread": "스프레드", diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index 5125c2dcc4..9a83fb130d 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -495,6 +495,7 @@ "top_markets": "Лучшие рынки" }, "exchange": { + "add_quote": "Add", "asks": "Ордера на Продажу", "atr": "Средний истинный диапазон", "balance": "Баланс", @@ -521,6 +522,7 @@ "confirm_sell": "Ваш ордер в %(diff)s раз ниже, чем самая высокая ставка, Вы уверены?", "core_rate": "Уровень выплат", + "custom_quote": "Add a custom quote", "deposit": "Пополнить счет", "description": "Описание", "ema": "Экспоненциальная скользящая средняя", @@ -556,6 +558,8 @@ "use": "Использовать" }, "more": "Найти рынки", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "Мои запросы", "my_bids": "Мои ставки", "my_history": "Мои сделки", @@ -577,8 +581,10 @@ "price_market": "Рыночная цена", "quantity": "Количество", "quote": "Валюта котировки:", + "quote_selection": "Modify quote selection", "quote_supply": "Назначить запас", "receive": "Получить", + "remove": "Remove", "rsi": "Индекс относительной прочности", "search": "Искать здесь другие рынки", "sell": "Продать", @@ -590,6 +596,7 @@ "short": "Сократить", "show_asks": "Показать все запросы", "show_bids": "Показать все заявки", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Показывать только {star_icon}", "sma": "Простая скользящая средняя", "spread": "Спред", diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index 78b9a8cdd7..2c1a92f173 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -487,6 +487,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "Satış emirleri", "atr": "Ortalama Gerçek Fiyat Aralığı", "balance": "Bakiye", @@ -513,6 +514,7 @@ "confirm_sell": "Emri teyit et: Sat %(sell_amount)s %(sell_symbol)s fiyat %(price_amount)s %(price_symbol)s", "core_rate": "Ücret Oranı", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "Üssel Hareketli Ortalama", @@ -549,6 +551,8 @@ "use": "Use" }, "more": "Piyasa bul", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "Satış Fiyatlarım", "my_bids": "Alış Fiyatlarım", "my_history": "Önceki İşlemlerim", @@ -570,8 +574,10 @@ "price_market": "Market Price", "quantity": "Miktar", "quote": "Quote currency:", + "quote_selection": "Modify quote selection", "quote_supply": "Karşıt arzı", "receive": "Tahsil", + "remove": "Remove", "rsi": "Relatif Güç İndeksi", "search": "Search for more markets here", "sell": "Satış -", @@ -583,6 +589,7 @@ "short": "Kısa pozisyon", "show_asks": "Tümünü göster", "show_bids": "Tüm alışları göster", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "Basit Hareketli Ortalama", "spread": "Makas", diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index 5667fe6bf6..35d6036ad8 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -467,6 +467,7 @@ "top_markets": "Top Markets" }, "exchange": { + "add_quote": "Add", "asks": "卖单", "atr": "平均真实波幅(ATR)", "balance": "我的余额", @@ -491,6 +492,7 @@ "你在一个没有委托买单的市场下了一个卖单,确定下单吗?", "confirm_sell": "你的委单价低于最高买入价 %(diff)s 倍,确定下单吗?", "core_rate": "手续费率", + "custom_quote": "Add a custom quote", "deposit": "Deposit", "description": "Description", "ema": "指数移动平均线(EMA)", @@ -526,6 +528,8 @@ "use": "Use" }, "more": "搜索更多市场", + "move_down": "Move down", + "move_up": "Move up", "my_asks": "我的卖单", "my_bids": "我的买单", "my_history": "我的交易历史", @@ -547,8 +551,10 @@ "price_market": "Market Price", "quantity": "数量", "quote": "报价货币:", + "quote_selection": "Modify quote selection", "quote_supply": "标价资产供应量", "receive": "获得", + "remove": "Remove", "rsi": "相对强弱指数(RSI)", "search": "搜索更多交易对", "sell": "卖出", @@ -560,6 +566,7 @@ "short": "做空", "show_asks": "显示所有卖单", "show_bids": "显示所有买单", + "show_only_liquid": "Show liquid markets only", "show_only_star_formatter": "Show {star_icon} only", "sma": "算数移动平均线(SMA)", "spread": "买卖价差", diff --git a/app/branding.js b/app/branding.js index 080056f336..a78bd692fe 100644 --- a/app/branding.js +++ b/app/branding.js @@ -75,7 +75,7 @@ export function getUnits() { */ export function getMyMarketsBases() { - return ["USD", "OPEN.BTC", "CNY", "BTS", "BTC"]; + return ["BTC", "ETH", "BTS", "USD", "CNY"]; } /** diff --git a/app/components/Exchange/MyMarkets.jsx b/app/components/Exchange/MyMarkets.jsx index 993c63b1ad..7a2f4654b8 100644 --- a/app/components/Exchange/MyMarkets.jsx +++ b/app/components/Exchange/MyMarkets.jsx @@ -18,12 +18,16 @@ import {debounce} from "lodash-es"; import AssetSelector from "../Utility/AssetSelector"; import counterpart from "counterpart"; import LoadingIndicator from "../LoadingIndicator"; -import {ChainValidation} from "bitsharesjs"; +import {ChainValidation, ChainStore} from "bitsharesjs"; import debounceRender from "react-debounce-render"; +import ZfApi from "react-foundation-apps/src/utils/foundation-api"; +import {gatewayPrefixes} from "common/gateways"; +import QuoteSelectionModal from "./QuoteSelectionModal"; class MarketGroup extends React.Component { static defaultProps = { - maxRows: 20 + maxRows: 20, + onlyLiquid: false }; constructor(props) { @@ -159,14 +163,14 @@ class MarketGroup extends React.Component { case "quoteSupply": return ( - + ); case "baseSupply": return ( - + ); @@ -203,6 +207,13 @@ class MarketGroup extends React.Component { let marketRows = markets .map(market => { + if ( + this.props.onlyLiquid && + marketStats.get(market.id) && + marketStats.get(market.id).volumeBase == 0 + ) { + return null; + } return ( ; - const myMarketTab = activeTab === "my-market"; - - let defaultBases = preferredBases.map(a => a); - - if (!myMarketTab) { - preferredBases = preferredBases.clear(); - preferredBases = preferredBases.push(this.state.activeFindBase); - } - - // Add some default base options - // let preferredBases = [coreSymbol, "BTC", "USD", "CNY"]; - let baseGroups = {}; - - let bases = [ - // coreSymbol, "BTC", "CNY", "USD" - ]; - - /* In the find-market tab, only use market tab 0 */ - if (!myMarketTab) activeMarketTab = 0; - - searchAssets - .filter(a => { - if (lookupBase && lookupBase.length) { - return a.symbol.indexOf(lookupBase) === 0; - } - return a.symbol.indexOf(lookupQuote) !== -1; - }) - .forEach(asset => { - if (lookupBase && lookupBase.length) { - if (asset.symbol.indexOf(lookupBase) === 0) { - bases.push(asset.symbol); - } - } else if (preferredBases.includes(asset.symbol)) { - if ( - asset.symbol.length >= lookupQuote.length && - asset.symbol.length < lookupQuote.length + 3 - ) { - bases.push(asset.symbol); - } - } - }); - - bases = bases.concat( - preferredBases - .filter(a => { - if (!lookupBase || !lookupBase.length) { - return true; - } - return a.indexOf(lookupBase) === 0; - }) - .toArray() + const { + activeTab, + lookupQuote, + lookupBase, + myMarketFilter, + activeMarketTab + } = this.state; + const possibleGatewayAssets = gatewayPrefixes.reduce( + (assets, prefix) => { + preferredBases.forEach(a => { + assets.push(`${prefix}.${a}`); + }); + return assets; + }, + [] ); - bases = bases.filter(base => { - if (lookupBase && lookupBase.length > 1) { - return base.indexOf(lookupBase) === 0; - } else { - return true; - } - }); + let bases = this._getBases(); + let allMarkets = [], + baseGroups = {}; + let otherMarkets = []; - let allMarkets = []; + const myMarketTab = activeTab === "my-market"; if (searchAssets.size) { searchAssets @@ -647,17 +611,27 @@ class MyMarkets extends React.Component { return true; }); - allMarkets = Immutable.Map(allMarkets); - let activeMarkets = myMarketTab ? defaultMarkets : allMarkets; + let activeMarkets = myMarketTab + ? defaultMarkets + : Immutable.Map(allMarkets); if (myMarketTab && userMarkets.size) { userMarkets.forEach((market, key) => { - activeMarkets = activeMarkets.set(key, market); + if (!activeMarkets.has(key)) + activeMarkets = activeMarkets.set(key, market); }); } - if (activeMarkets.size > 0) { - otherMarkets = activeMarkets + function filterAndSeparateMarkets( + base, + matchBases, + markets, + baseGroups, + otherMarkets + ) { + let others = markets .filter(a => { + if (a.base === a.quote) return false; + /* Return search results in the Find Markets Tab */ if (!myMarketTab) { if (lookupQuote.length < 1) { return false; @@ -665,29 +639,38 @@ class MyMarkets extends React.Component { return a.quote.indexOf(lookupQuote) !== -1; } else { + /* Return filtered markets if a filter is input */ const ID = a.quote + "_" + a.base; - if (!!this.state.myMarketFilter) { - return ID.indexOf(this.state.myMarketFilter) !== -1; + if (!!myMarketFilter) { + return ID.indexOf(myMarketFilter) !== -1; } + /* Return only starred markets if that option is checked */ if (onlyStars && !starredMarkets.has(ID)) { return false; } + /* Else return all markets */ return true; } }) .map(market => { let marketID = market.quote + "_" + market.base; - if (preferredBases.includes(market.base)) { - if (!baseGroups[market.base]) { - baseGroups[market.base] = []; + if (matchBases.indexOf(market.base) !== -1) { + if (!baseGroups[base]) { + baseGroups[base] = []; } - baseGroups[market.base].push({ + let marketObject = { id: marketID, quote: market.quote, base: market.base - }); + }; + if (!baseGroups[base].find(m => m.id === marketID)) + baseGroups[base].push(marketObject); return null; - } else { + } else if ( + !preferredBases.includes(market.base) && + possibleGatewayAssets.indexOf(market.base) === -1 + ) { + // console.log("Adding to other markets:", base, market.base, preferredBases.toJS()) return { id: marketID, quote: market.quote, @@ -695,15 +678,139 @@ class MyMarkets extends React.Component { }; } }) - .filter(a => { - return a !== null; - }) + .filter(a => !!a) .take(myMarketTab ? 100 : 20) .toArray(); + return {otherMarkets: others.concat(otherMarkets), baseGroups}; } - const hasOthers = otherMarkets && otherMarkets.length; + if (activeMarkets.size > 0) { + const currentBase = myMarketTab + ? preferredBases.get(activeMarketTab) + : this.state.activeFindBase; + + ({otherMarkets, baseGroups} = filterAndSeparateMarkets( + currentBase, + [currentBase], + activeMarkets, + baseGroups, + otherMarkets + )); + + /* Check for possible gateway versions of the asset */ + gatewayPrefixes.forEach(prefix => { + let possibleGatewayAssetName = `${prefix}.${currentBase}`; + let gatewayAsset = ChainStore.getAsset( + possibleGatewayAssetName + ); + /* If the gateway offers an asset for this base, add it to the list */ + if (!!gatewayAsset) { + let gatewayMarkets = activeMarkets + .map(m => { + if (m.quote === m.base) return null; + let newID = `${ + m.quote + }_${possibleGatewayAssetName}`; + if (activeMarkets.has(newID)) return null; + return { + base: possibleGatewayAssetName, + quote: m.quote + }; + }, {}) + .filter(m => !!m); + ({otherMarkets, baseGroups} = filterAndSeparateMarkets( + currentBase, + [currentBase, possibleGatewayAssetName], + gatewayMarkets, + baseGroups, + otherMarkets + )); + } + }); + } + return {baseGroups, otherMarkets}; + } + + _getBases() { + let {preferredBases, searchAssets} = this.props; + let {lookupQuote, lookupBase} = this.state; + + let bases = searchAssets + .filter(a => { + if (lookupBase && lookupBase.length) { + return a.symbol.indexOf(lookupBase) === 0; + } + return a.symbol.indexOf(lookupQuote) !== -1; + }) + .map(asset => { + if (lookupBase && lookupBase.length) { + if (asset.symbol.indexOf(lookupBase) === 0) { + return asset.symbol; + } + } else if (preferredBases.includes(asset.symbol)) { + if ( + asset.symbol.length >= lookupQuote.length && + asset.symbol.length < lookupQuote.length + 3 + ) { + return asset.symbol; + } + } + }) + .filter(a => !!a) + .toArray(); + + bases = bases.concat( + preferredBases + .filter(a => { + if (!lookupBase || !lookupBase.length) { + return true; + } + return a.indexOf(lookupBase) === 0; + }) + .toArray() + ); + + bases = bases.filter(base => { + if (lookupBase && lookupBase.length > 1) { + return base.indexOf(lookupBase) === 0; + } else { + return true; + } + }); + + return bases; + } + + render() { + let { + starredMarkets, + marketStats, + columns, + assetsLoading, + preferredBases, + current, + viewSettings, + listHeight + } = this.props; + let {activeMarketTab, activeTab} = this.state; + + const myMarketTab = activeTab === "my-market"; + let defaultBases = preferredBases.map(a => a); + + if (!myMarketTab) { + preferredBases = preferredBases.clear(); + preferredBases = preferredBases.push(this.state.activeFindBase); + } + + // Add some default base options + // let preferredBases = [coreSymbol, "BTC", "USD", "CNY"]; + + /* In the find-market tab, only use market tab 0 */ + if (!myMarketTab) activeMarketTab = 0; + + let {baseGroups, otherMarkets} = this._getMarkets(); + const hasOthers = otherMarkets && otherMarkets.length; let hc = "mymarkets-header clickable"; let starClass = cnames(hc, {inactive: !myMarketTab}); let allClass = cnames(hc, {inactive: myMarketTab}); @@ -761,41 +868,56 @@ class MyMarkets extends React.Component { {myMarketTab ? (
    - -
    + + + + + +
    +
    - + {base} ); })} @@ -950,6 +1072,18 @@ class MyMarkets extends React.Component { ) : null} + + {/* Quote edit tab */} +
  • { + ZfApi.publish("quote_selection", "open"); + }} + className="mymarkets-tab" + > +  +  +
  • ); })} @@ -1019,6 +1156,7 @@ class MyMarkets extends React.Component { /> ) : null}
    +
    ); } @@ -1039,6 +1177,10 @@ export default connect(MyMarketsWrapper, { getProps() { return { starredMarkets: SettingsStore.getState().starredMarkets, + onlyLiquid: SettingsStore.getState().viewSettings.get( + "onlyLiquid", + true + ), defaultMarkets: SettingsStore.getState().defaultMarkets, viewSettings: SettingsStore.getState().viewSettings, preferredBases: SettingsStore.getState().preferredBases, diff --git a/app/components/Exchange/QuoteSelectionModal.jsx b/app/components/Exchange/QuoteSelectionModal.jsx new file mode 100644 index 0000000000..0e8ad587a0 --- /dev/null +++ b/app/components/Exchange/QuoteSelectionModal.jsx @@ -0,0 +1,179 @@ +import React from "react"; +import Icon from "../Icon/Icon"; +import BaseModal from "../Modal/BaseModal"; +import AssetSelector from "../Utility/AssetSelector"; +import SettingsActions from "actions/SettingsActions"; +import Translate from "react-translate-component"; + +export default class QuoteSelectionModal extends React.Component { + constructor() { + super(); + + this.state = { + backingAsset: "", + error: false, + valid: false + }; + } + + _onMoveUp(quote) { + const idx = this.props.quotes.findIndex(q => q === quote); + SettingsActions.modifyPreferedBases({ + oldIndex: idx, + newIndex: idx - 1 + }); + } + + _onMoveDown(quote) { + const idx = this.props.quotes.findIndex(q => q === quote); + SettingsActions.modifyPreferedBases({ + oldIndex: idx, + newIndex: idx + 1 + }); + } + + _onRemove(quote) { + const idx = this.props.quotes.findIndex(q => q === quote); + if (idx >= 0) { + SettingsActions.modifyPreferedBases({ + remove: idx + }); + } + } + + _onAdd(quote) { + const idx = this.props.quotes.findIndex(q => q === quote.get("symbol")); + if (idx === -1) { + SettingsActions.modifyPreferedBases({ + add: quote.get("symbol") + }); + } + } + + _onInputBackingAsset(asset) { + this.setState({ + backingAsset: asset.toUpperCase(), + error: null + }); + } + + _onFoundBackingAsset(asset) { + if (asset) { + console.log( + "asset", + asset.get("symbol"), + this.props.quotes.includes(asset.get("symbol")) + ); + if (!this.props.quotes.includes(asset.get("symbol"))) { + this.setState({isValid: true}); + } else { + this.setState({ + error: "Asset already being used", + isValid: false + }); + } + } + } + + render() { + const {error} = this.state; + const quoteCount = this.props.quotes.size; + return ( + +
    + + + + + + + + + + + {this.props.quotes.map((q, idx) => { + return ( + + + + + + + + ); + })} + +
    + + + + + + + + +
    {idx + 1}{q} + {idx !== quoteCount - 1 && ( + + )} + + {idx !== 0 && ( + + )} + + {quoteCount > 1 && ( + + )} +
    + +
    +
    +
    + +
    + +
    {error}
    +
    +
    +
    + ); + } +} diff --git a/app/components/Icon/icon.scss b/app/components/Icon/icon.scss index a2d175c776..67c0945b4d 100644 --- a/app/components/Icon/icon.scss +++ b/app/components/Icon/icon.scss @@ -1,59 +1,71 @@ .icon { - position: relative; - top: 1px; + position: relative; + top: 1px; } -.icon > svg, span.icon { - width: 1rem; - height: 1rem; +.icon > svg, +span.icon { + width: 1rem; + height: 1rem; } -.icon-14px > svg, span.icon-14px { - width: 16px; - height: 16px; +.icon-14px > svg, +span.icon-14px { + width: 16px; + height: 16px; } -.icon-32px > svg, span.icon-32px { - width: 32px; - height: 32px; +.icon-32px > svg, +span.icon-32px { + width: 32px; + height: 32px; } -.icon-1_5x > svg, span.icon-1_5x { - width: 1.5rem; - height: 1.5rem; +.icon-1_5x > svg, +span.icon-1_5x { + width: 1.5rem; + height: 1.5rem; } -.icon-2x > svg, span.icon-2x { - width: 2rem; - height: 2rem; +.icon-2x > svg, +span.icon-2x { + width: 2rem; + height: 2rem; } -.icon-3x > svg, span.icon-3x { - width: 3.45rem; - height: 3.45rem; +.icon-3x > svg, +span.icon-3x { + width: 3.45rem; + height: 3.45rem; } -.icon-4x > svg, span.icon-4x { - width: 4.60rem; - height: 4.60rem; +.icon-4x > svg, +span.icon-4x { + width: 4.6rem; + height: 4.6rem; } -.icon-5x > svg, span.icon-5x { - width: 5.75rem; - height: 5.75rem; - margin: 24px 0 24px 0; +.icon-5x > svg, +span.icon-5x { + width: 5.75rem; + height: 5.75rem; + margin: 24px 0 24px 0; } -.icon-10x > svg, span.icon-10x { - width: 10rem; - height: 10rem; - margin: 24px 0 24px 0; +.icon-10x > svg, +span.icon-10x { + width: 10rem; + height: 10rem; + margin: 24px 0 24px 0; } .icon.fill-black > svg > path { - fill:black; + fill: black; } .icon.rotate90 > svg { transform: rotate(90deg); } +.icon.rotate180 > svg { + transform: rotate(180deg); +} diff --git a/app/components/Utility/AssetSelector.jsx b/app/components/Utility/AssetSelector.jsx index ac1153ef00..f05c234db1 100644 --- a/app/components/Utility/AssetSelector.jsx +++ b/app/components/Utility/AssetSelector.jsx @@ -64,7 +64,7 @@ class AssetSelector extends React.Component { assetInput: PropTypes.string, // the current value of the account selector, the string the user enters asset: ChainTypes.ChainAsset, // account object retrieved via BindToChainState decorator (not input) tabIndex: PropTypes.number, // tabindex property to be passed to input tag - disableActionButton: PropTypes.string // use it if you need to disable action button + disableActionButton: PropTypes.bool // use it if you need to disable action button }; static defaultProps = { diff --git a/app/stores/SettingsStore.js b/app/stores/SettingsStore.js index 3a3c7f68cb..1df3605232 100644 --- a/app/stores/SettingsStore.js +++ b/app/stores/SettingsStore.js @@ -48,7 +48,8 @@ class SettingsStore { onClearSettings: SettingsActions.clearSettings, onSwitchLocale: IntlActions.switchLocale, onSetUserMarket: SettingsActions.setUserMarket, - onUpdateLatencies: SettingsActions.updateLatencies + onUpdateLatencies: SettingsActions.updateLatencies, + onModifyPreferedBases: SettingsActions.modifyPreferedBases }); this.initDone = false; @@ -183,6 +184,7 @@ class SettingsStore { if (this.initDone) resolve(); this.starredKey = this._getChainKey("markets"); this.marketsKey = this._getChainKey("userMarkets"); + this.basesKey = this._getChainKey("preferredBases"); // Default markets setup let topMarkets = { markets_4018d784: getMyMarketsQuotes(), @@ -208,28 +210,15 @@ class SettingsStore { let coreAsset = coreAssets[this.starredKey] || "BTS"; this.defaults.unit[0] = coreAsset; - let chainBases = bases[this.starredKey] || bases.markets_4018d784; - this.preferredBases = Immutable.List(chainBases); - - function addMarkets(target, base, markets) { - markets - .filter(a => { - return a !== base; - }) - .forEach(market => { - target.push([ - `${market}_${base}`, - {quote: market, base: base} - ]); - }); - } + let defaultBases = bases[this.starredKey] || bases.markets_4018d784; + let storedBases = ss.get(this.basesKey, []); + this.preferredBases = Immutable.List( + storedBases.length ? storedBases : defaultBases + ); - let defaultMarkets = []; - let chainMarkets = topMarkets[this.starredKey] || []; - this.preferredBases.forEach(base => { - addMarkets(defaultMarkets, base, chainMarkets); - }); + this.chainMarkets = topMarkets[this.starredKey] || []; + let defaultMarkets = this._getDefaultMarkets(); this.defaultMarkets = Immutable.Map(defaultMarkets); this.starredMarkets = Immutable.Map(ss.get(this.starredKey, [])); this.userMarkets = Immutable.Map(ss.get(this.marketsKey, {})); @@ -239,6 +228,29 @@ class SettingsStore { }); } + _getDefaultMarkets() { + let markets = []; + + this.preferredBases.forEach(base => { + addMarkets(markets, base, this.chainMarkets); + }); + + function addMarkets(target, base, markets) { + markets + .filter(a => { + return a !== base; + }) + .forEach(market => { + target.push([ + `${market}_${base}`, + {quote: market, base: base} + ]); + }); + } + + return markets; + } + getSetting(setting) { return this.settings.get(setting); } @@ -441,6 +453,33 @@ class SettingsStore { getExhchangeLastExpiration() { return this.getExchangeSettings("lastExpiration"); } + + onModifyPreferedBases(payload) { + if ("newIndex" in payload && "oldIndex" in payload) { + /* Reorder */ + let current = this.preferredBases.get(payload.newIndex); + this.preferredBases = this.preferredBases.set( + payload.newIndex, + this.preferredBases.get(payload.oldIndex) + ); + this.preferredBases = this.preferredBases.set( + payload.oldIndex, + current + ); + } else if ("remove" in payload) { + /* Remove */ + this.preferredBases = this.preferredBases.delete(payload.remove); + let defaultMarkets = this._getDefaultMarkets(); + this.defaultMarkets = Immutable.Map(defaultMarkets); + } else if ("add" in payload) { + /* Add new */ + this.preferredBases = this.preferredBases.push(payload.add); + let defaultMarkets = this._getDefaultMarkets(); + this.defaultMarkets = Immutable.Map(defaultMarkets); + } + + ss.set(this.basesKey, this.preferredBases.toArray()); + } } export default alt.createStore(SettingsStore, "SettingsStore"); From dedb51e668523821f157777c5b3ee8771545bfb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Fri, 20 Jul 2018 06:43:51 +0200 Subject: [PATCH 15/69] Close #1701: Implement an advanced ping strategy (#1702) - fixes bug when no connection can be established (url in urlChangeCallback is then undefined) - urls that fail are removed from ping map Signed-off-by: Stefan Schiessl --- app/assets/locales/locale-en.json | 4 +- app/components/Settings/AccessSettings.jsx | 2 +- app/routerTransition.js | 186 +++++++++++++-------- 3 files changed, 121 insertions(+), 71 deletions(-) diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index aea0f56d24..ac10301992 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -412,7 +412,9 @@ "browser": "Unsupported browser", "browser_text": "The Browser you are using has not been fully tested to support the %(wallet_name)s Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", - "check_latency": "Running latency checks...", + "check_latency": "Running latency checks ...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Connected", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", diff --git a/app/components/Settings/AccessSettings.jsx b/app/components/Settings/AccessSettings.jsx index 292f1e601b..611ece8ebe 100644 --- a/app/components/Settings/AccessSettings.jsx +++ b/app/components/Settings/AccessSettings.jsx @@ -413,7 +413,7 @@ class AccessSettings extends React.Component { _recalculateLatency(event, feedback) { feedback("settings.pinging"); - routerTransitioner.doLatencyUpdate(true, 4).finally(() => { + routerTransitioner.doLatencyUpdate(true, null).finally(() => { feedback(); }); } diff --git a/app/routerTransition.js b/app/routerTransition.js index fe9f34211c..beede5612a 100644 --- a/app/routerTransition.js +++ b/app/routerTransition.js @@ -46,38 +46,28 @@ class RouterTransitioner { // transitionDone is called within Promises etc., rebind it to always reference to RouterTransitioner object as // this this._transitionDone = this._transitionDone.bind(this); + + // function that can be provided to willTransitionTo + this._statusCallback = null; } /** * Is called once when router is initialized, and then if a connection error occurs or user manually * switches nodes * - * @param callback argument as given by Route onEnter * @param appInit true when called via router, false false when node is manually selected in access settings + * @param statusCallback null function can be given by the requesting component to notify the user of status changes * @returns {Promise} */ willTransitionTo(appInit = true, statusCallback = () => {}) { - if (this.isTransitionInProgress()) return; - this.statusCallback = statusCallback; + if (this.isTransitionInProgress()) + return new Promise((resolve, reject) => { + resolve(); + }); + this._statusCallback = statusCallback; this._willTransitionToInProgress = true; return new Promise((resolve, reject) => { - // Bypass the app init chain for the migration path which is only used at bitshares.org/wallet - if (__DEPRECATED__) { - ChainConfig.setChainId(chainIds.MAIN_NET); - let dbPromise = iDB.init_instance(this._getIndexDBImpl()) - .init_promise; - return dbPromise.then(() => { - Promise.all([ - WalletDb.loadDbData().then(() => { - // console.log("wallet init done"); - this._transitionDone(resolve); - }), - WalletManagerStore.init() - ]); - }); - } - // dict of apiServer url as key and the latency as value const apiLatencies = SettingsStore.getState().apiLatencies; let latenciesEstablished = Object.keys(apiLatencies).length > 0; @@ -105,14 +95,8 @@ class RouterTransitioner { if ( !latenciesEstablished || - Object.keys(apiLatencies).length < 10 + Object.keys(apiLatencies).length == 0 ) { - this._willTransitionToInProgress = counterpart.translate( - "settings.ping" - ); - this.statusCallback( - counterpart.translate("app_init.check_latency") - ); this.doLatencyUpdate(true) .then( this._initiateConnection.bind( @@ -142,14 +126,59 @@ class RouterTransitioner { this._willTransitionToInProgress = false; } + /** + * Updates the latency of all target nodes + * + * @param nodeUrls list of string nodes to update + * @returns {Promise} + */ + doQuickLatencyUpdate(nodeUrls) { + return new Promise((resolve, reject) => { + let url = this._connectionManager.url; + let urls = this._connectionManager.urls; + + if (typeof nodeUrls === "string") { + nodeUrls = [nodeUrls]; + } + this._connectionManager.url = nodeUrls[0]; + this._connectionManager.urls = nodeUrls.slice(1, nodeUrls.length); + + this._connectionManager + .checkConnections() + .then(res => { + console.log("Following nodes have been pinged:", res); + // update the latencies object + const apiLatencies = SettingsStore.getState().apiLatencies; + for (var nodeUrl in res) { + apiLatencies[nodeUrl] = res[nodeUrl]; + } + SettingsActions.updateLatencies(apiLatencies); + }) + .catch(err => { + console.log("doLatencyUpdate error", err); + }) + .finally(() => { + this._connectionManager.url = url; + this._connectionManager.urls = urls; + resolve(); + }); + }); + } + /** * Updates the latency of all target nodes * * @param refresh boolean true reping all existing nodes * false only reping all reachable nodes + * @param beSatisfiedWith integer if nodes with less than this integer latency are found, pinging is stopped + * @param range integer ping range amount of nodes at the same time, default 5 * @returns {Promise} */ - doLatencyUpdate(refresh = true, range = null) { + doLatencyUpdate(refresh = true, beSatisfiedWith = 200, range = 5) { + this.updateTransitionTarget( + counterpart.translate("app_init.check_latency") + ); + return new Promise((resolve, reject) => { // if for some reason this method is called before connections are setup via willTransitionTo, // initialize the manager @@ -176,21 +205,41 @@ class RouterTransitioner { current + 1, current + range ); - console.log( - current, - range, - thiz._connectionManager.url, - thiz._connectionManager.urls + thiz.updateTransitionTarget( + counterpart.translate( + "app_init.check_latency_feedback", + { + pinged: current, + totalToPing: urls.length + } + ) ); thiz._connectionManager .checkConnections() .then(res => { - console.log(res); + console.log( + "Following nodes have been pinged:", + res + ); // update the latencies object const apiLatencies = SettingsStore.getState() .apiLatencies; for (var nodeUrl in res) { apiLatencies[nodeUrl] = res[nodeUrl]; + // if we find a node that has less than beSatisfiedWith ms latency we stop pinging + if ( + beSatisfiedWith != null && + res[nodeUrl] < beSatisfiedWith + ) { + console.log( + "Found node " + + nodeUrl + + " with less than " + + beSatisfiedWith + + "ms, stopping latency update" + ); + current = urls.length; + } } SettingsActions.updateLatencies(apiLatencies); }) @@ -232,17 +281,15 @@ class RouterTransitioner { closeCb: this._onConnectionClose.bind(this), optionalApis: {enableOrders: true}, urlChangeCallback: url => { - console.log( - "fallback to new url:", - url, - "old", - this._willTransitionToInProgress - ); - /* Update connection status */ - this.statusCallback( - counterpart.translate("app_init.connecting", {server: url}) - ); - this._willTransitionToInProgress = url; + console.log("fallback to new url:", url); + if (!!url) { + // Update connection status + this.updateTransitionTarget( + counterpart.translate("app_init.connecting", { + server: url + }) + ); + } SettingsActions.changeSetting({ setting: "activeNode", value: url @@ -263,6 +310,13 @@ class RouterTransitioner { return !!this._willTransitionToInProgress; } + updateTransitionTarget(update) { + this._willTransitionToInProgress = update; + if (this._statusCallback != null) { + this._statusCallback(update); + } + } + getTransitionTarget() { if (this.isTransitionInProgress()) return this._willTransitionToInProgress; @@ -318,10 +372,10 @@ class RouterTransitioner { unsuitableSecurity = false, testNet = false ) { + if (latenciesMap == null) { + latenciesMap = SettingsStore.getState().apiLatencies; + } if (latencies) { - if (latenciesMap == null) { - latenciesMap = SettingsStore.getState().apiLatencies; - } // if there are no latencies, return all that are left after filtering latencies = Object.keys(latenciesMap).length > 0; } @@ -359,30 +413,22 @@ class RouterTransitioner { } return newEntry; }); - if (!latencies) { - return filtered; - } // now sort filtered = filtered.sort((a, b) => { - if (!latencies) { + // if both have latency, sort according to that + if (a.latency != null && b.latency != null) { + return a.latency - b.latency; + // sort testnet to the bottom + } else if (a.latency == null && b.latency == null) { if (this._isTestNet(a.url)) return -1; return 1; - } else { - // if both have latency, sort according to that - if (a.latency != null && b.latency != null) { - return a.latency - b.latency; - // sort testnet to the bottom - } else if (a.latency == null && b.latency == null) { - if (this._isTestNet(a.url)) return -1; - return 1; - // otherwise prefer the pinged one - } else if (a.latency != null && b.latency == null) { - return -1; - } else if (b.latency != null && a.latency == null) { - return 1; - } - return 0; + // otherwise prefer the pinged one + } else if (a.latency != null && b.latency == null) { + return -1; + } else if (b.latency != null && a.latency == null) { + return 1; } + return 0; }); // remove before release return filtered; @@ -453,7 +499,7 @@ class RouterTransitioner { if (appInit) { // only true if app is initialized - this.statusCallback( + this.updateTransitionTarget( counterpart.translate("app_init.connecting", { server: this._connectionManager.url }) @@ -515,6 +561,9 @@ class RouterTransitioner { level: "error", autoDismiss: 10 }); + let apiLatencies = SettingsStore.getState().apiLatencies; + delete apiLatencies[failingNodeUrl]; + SettingsActions.updateLatencies(apiLatencies); return Apis.close().then(() => { return this.willTransitionTo(true); }); @@ -545,12 +594,11 @@ class RouterTransitioner { * @private */ _onConnect(resolve, reject) { - // console.log(new Date().getTime(), "routerTransition onConnect", caller, "_connectInProgress", _connectInProgress); if (this._connectInProgress) { console.error("MULTIPLE CONNECT IN PROGRESS"); return; } - this.statusCallback(counterpart.translate("app_init.database")); + this.updateTransitionTarget(counterpart.translate("app_init.database")); this._connectInProgress = true; if (Apis.instance()) { if (!Apis.instance().orders_api()) From 72a34b1c83228dd2d48897b57d369679b52d95ed Mon Sep 17 00:00:00 2001 From: Ruslan Salikhov Date: Fri, 20 Jul 2018 09:52:57 +0500 Subject: [PATCH 16/69] Update russian translations (#1709) --- app/assets/locales/locale-ru.json | 100 +++++++++++++++--------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index 9a83fb130d..c46e0686dc 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -63,7 +63,7 @@ "Также DEX дает возможность создавать выпускаемые пользователем активы (user-issued assets - UIA), которые могут торговаться с помощью регистра ордеров против любого другого актива на платформе, как не требующего доверия, так и выпущенного пользователем. Самым известным эмитентом на платформе является OpenLedger, поддерживающий такие активы, как BTC, ETH, DASH, STEEM и многие другие", "intro_text_4": "Это уникальный микс традиционной и децентрализованной торговли, и всё это в таком знакомом для криптовалютных трейдеров интерфейсе биржи. Удачной торговли!", - "intro_text_title": "Добро пожаловать в BitShares DEX", + "intro_text_title": "Добро пожаловать в %(wallet_name)s", "login_with": "Войти при помощи", "market_actions": "Рыночные операции", "market_value": "Рыночная стоимость", @@ -87,7 +87,7 @@ "network_percentage": "Сеть", "referral_link": "Ваша реферальная ссылка", "referral_text": - "Дайте эту ссылку людям, которых Вы хотите пригласить в BitShares", + "Дайте эту ссылку людям, которых Вы хотите пригласить в %(wallet_name)s", "referrals": "Рефералы", "referrer": "Аффилированный Реферал", "registrar": "Регистратор", @@ -189,7 +189,7 @@ "portfolio": "Портфель", "propose_from": "Предложить от", "qty": "Кол-во", - "quote": "Котировка", + "quote": "Тикер", "recent": "Последние действия", "reset_orders": "Сбросить", "restore": "Восстановить", @@ -402,7 +402,7 @@ "workers_short": "Работники" }, "voting": "Голосование", - "welcome": "Добро пожаловать в BitShares", + "welcome": "Добро пожаловать в %(wallet_name)s", "whitelist": { "add": "Добавить в белый список", "add_black": "Добавить в черный список", @@ -425,11 +425,12 @@ "app_init": { "browser": "Неподдерживаемый браузер", "browser_text": - "Браузер, который Вы используете, не тестировался на предмет поддержки кошелька BitShares. Мы настоятельно рекомендуем Вам сделать резервную копию вашего локального кошелька и импортировать его, используя браузер Chrome, пока мы не проведем полное тестирование выбранного Вами браузера. Мы не несем ответственности за использование Вами данного браузера.", - "check_latency": "Running latency checks...", + "Браузер, который Вы используете, не тестировался на поддержку кошелька %(wallet_name)s. Мы настоятельно рекомендуем Вам сделать резервную копию вашего локального кошелька и импортировать его, используя браузер Chrome, пока мы не найдем время, чтобы провести полное тестирование выбранного Вами браузера. Мы не несем ответственности за использование Вами данного браузера.", + "check_latency": "Выполняется проверка задержки...", "connected": "Соединение установлено", "connecting": "Подключение к серверу API: %(server)s", - "database": "Connection established, initializing local databases", + "database": + "Соединение установлено, идет инициализация локальных баз данных", "not_connected": "Нет соединения", "retry": "Повторить попытку", "title": "Проблемы инициализации приложения", @@ -446,14 +447,14 @@ "below": "Ваш уровень гарантийного обеспечения ниже %(mr)s, что не допускается.", "below_info": - "Your position is below the required maintenance collateral ratio! Increasing collateral ratio is allowed, debt can only be decreased.", + "Коэффициент залогового обеспечения вашей позиции находится ниже требуемого! Залоговый коэффициент можно увеличить, тогда как долг можно только уменьшить.", "below_ratio_mcr_update": - "Your collateral ratio is blow your original %(ocr)s. Only increased ratio is allowed on margin called orders", + "Ваш залоговый коэффициент ниже вашего оригинального %(ocr)s. Для попавших под маржин колл ордеров доступен только увеличенный коэффициент.", "close": "Ваш уровень обеспечения близок к %(mr)s, что означает, что в случае падения цены, в отношении данной позиции будет совершён марджин колл.", "collateral": "Недостаточный остаток на счете", "increased_debt_on_margin_call": - "You increased your debt, which is not allowed when updating a margin called position" + "Вы увеличили свой долг, что является недопустимым действием при обновлении попавшей под маржин колл позиции" }, "maximize_debt_set_ratio_slider": "Прежде чем максимизировать долг, вы должны задать коэффициент залогового обеспечения", @@ -470,13 +471,13 @@ "cancel": "Отменить", "connection": { "automatic_reconnect": - " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", - "manual_reconnect": "Reconnect now", + " Повторная попытка соединения будет совершена автоматически через %(reconnect_in_seconds)s секунд.", + "manual_reconnect": "Переподключиться", "out_of_sync": - "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", - "title_out_of_sync": "Connection out of sync", + "Ваше соединение потеряно %(out_of_sync_seconds)s секунд.", + "title_out_of_sync": "Соединение потеряно", "want_to_reconnect": - "If the connection can be recovered this message will disappear automatically." + "Если соединение восстановится, данное сообщение исчезнет автоматически." }, "counterpart": { "formats": { @@ -495,7 +496,7 @@ "top_markets": "Лучшие рынки" }, "exchange": { - "add_quote": "Add", + "add_quote": "Добавить", "asks": "Ордера на Продажу", "atr": "Средний истинный диапазон", "balance": "Баланс", @@ -522,7 +523,7 @@ "confirm_sell": "Ваш ордер в %(diff)s раз ниже, чем самая высокая ставка, Вы уверены?", "core_rate": "Уровень выплат", - "custom_quote": "Add a custom quote", + "custom_quote": "Добавить свой тикер", "deposit": "Пополнить счет", "description": "Описание", "ema": "Экспоненциальная скользящая средняя", @@ -530,7 +531,7 @@ "feed_price": "Котировка", "filter": "Фильтр...", "flip": "Инвертировать", - "group_order_limit": "группа", + "group_order_limit": "Групповой", "hide": "Скрыть", "highest_bid": "Наивысшая ставка", "history": "Рыночные сделки", @@ -558,19 +559,19 @@ "use": "Использовать" }, "more": "Найти рынки", - "move_down": "Move down", - "move_up": "Move up", + "move_down": "Вниз", + "move_up": "Вверх", "my_asks": "Мои запросы", "my_bids": "Мои ставки", "my_history": "Мои сделки", "my_orders": "Мои открытые ордера", "native": "Встроенная", "new": "Новый", - "no_asks": "No asks", + "no_asks": "Нет предложений на продажу", "no_balance": "Недостаточно средств", - "no_bids": "No bids", + "no_bids": "Нет предложений на покупку", "no_data": "Нет данных", - "no_orders": "No orders", + "no_orders": "Нет ордеров", "order_depth": "Глубина Рынка", "others": "Другие", "overbought": "Перекуплен", @@ -581,10 +582,10 @@ "price_market": "Рыночная цена", "quantity": "Количество", "quote": "Валюта котировки:", - "quote_selection": "Modify quote selection", + "quote_selection": "Изменить тикер базовой валюты", "quote_supply": "Назначить запас", "receive": "Получить", - "remove": "Remove", + "remove": "Удалить", "rsi": "Индекс относительной прочности", "search": "Искать здесь другие рынки", "sell": "Продать", @@ -596,7 +597,7 @@ "short": "Сократить", "show_asks": "Показать все запросы", "show_bids": "Показать все заявки", - "show_only_liquid": "Show liquid markets only", + "show_only_liquid": "Показать только ликвидные рынки", "show_only_star_formatter": "Показывать только {star_icon}", "sma": "Простая скользящая средняя", "spread": "Спред", @@ -828,13 +829,13 @@ "loading": "Загрузка...", "nosync": "Ваш активный узел не синхронизирован", "synced": "Синхронизирован", - "title": "BitShares", + "title": "%(wallet_name)s", "unsynced": "Не синхронизирован", "update_available": "ДОСТУПНО ОБНОВЛЕНИЕ" }, "gateway": { "add_funds": - "Быстро и легко добавляйте средства на Ваш аккаунт BitShares %(account)s. Эта услуга предоставляется Openledger.", + "Быстро и легко добавьте средства на Ваш аккаунт %(wallet_name)s %(account)s. Эта услуга предоставляется Openledger.", "address": "Адрес", "address_with_memo": "%(address)s с примечанием %(memo)s", @@ -976,7 +977,7 @@ "withdraw": "Вывод", "withdraw_coin": "Вывести %(coin)s (%(symbol)s)", "withdraw_funds": - "Вы собираетесь вывести средства с Вашего аккаунта BitShares на Ваш внешний %(asset)s аккаунт.", + "Вы собираетесь вывести средства с Вашего аккаунта %(wallet_name)s на Ваш внешний %(asset)s аккаунт.", "withdraw_history_status": { "audited": "аудит завершен", "auditing": "аудит вывода", @@ -1004,7 +1005,7 @@ "account": "Аккаунт", "account_notify": "Активный аккаунт в настоящее время %(account)s", "account_value": "Оценка", - "accounts_manage": "Учетные записи", + "accounts_manage": "Управление аккаунтами", "collateral_ratio": "Коэффициент покрытия", "create_account": "Создать аккаунт", "create_asset": "Создать актив", @@ -1023,7 +1024,7 @@ "payments_beta": "Отправить (бета)", "payments_legacy": "Отправить (стар.)", "settings": "Настройки", - "title": "Пользовательский интерфейс BitShares", + "title": "Пользовательский интерфейс %(wallet_name)s", "unlock": "Вход в локальный кошелек", "unlock_password": "Войти используя пароль", "unlock_short": "Войти", @@ -1071,7 +1072,7 @@ "borrow": "Занять", "buy": "Купить" }, - "download": "Скачать новую версию интерфейса BitShares", + "download": "Скачать новую версию интерфейса %(wallet_name)s", "excel": "Скачать CSV-файл", "eye": "Скрыть узел", "eye-striked": "Показать узел", @@ -1096,7 +1097,7 @@ "common": "Нажмите, чтобы разблокировать свой аккаунт", "enable_auto_scroll": "Разрешить автопрокрутку" }, - "manage_accounts": "Manage Accounts", + "manage_accounts": "Управление аккаунтами", "minus_circle": { "disapproved": "Отклоненные", "no": "Нет", @@ -1173,9 +1174,9 @@ "Дабы обеспечить повышенную безопасность веб-кошелька, мы переносим его на указанный ниже адрес. Обязательно обновите любые закладки, которые у вас есть.", "text_1": "Обнаружен локальный кошелек", "text_2": - "Пожалуйста, создайте резервную копию своего кошелька и восстановите файл резервной копии на https://wallet.bitshares.org, который станет вашим новым адресом для веб-кошелька. Спасибо за ваше содействие.", + "Пожалуйста, создайте резервную копию своего кошелька и восстановите файл резервной копии на %(wallet_url)s, который станет вашим новым адресом для веб-кошелька. Спасибо за содействие.", "text_3": - "Начиная с этого момента, пожалуйста, используйте
    https://wallet.bitshares.org, ваши существующие учетные данные также позволят вам логиниться там.", + "Начиная с этого момента, пожалуйста, используйте %(wallet_url)s, ваши существующие учетные данные также позволят вам логиниться там.", "title": "Уведомление" }, "modal": { @@ -1255,7 +1256,7 @@ "address_not_valid": "Неверный адрес", "amount": "Сумма на вывод", "available": "Доступно: ", - "bitshares_account": "Отправить на аккаунт в Bitshares", + "bitshares_account": "Отправить на аккаунт %(wallet_name)s", "cancel": "Отменить", "cannot_cover": "Недостаточно средств", "estimated_value": "Ориентировочная стоимость", @@ -1324,10 +1325,10 @@ "lifetime_upgrade_account": "{account} обновился до пожизненного членства", "limit_order_buy": - "{account} разместил ордер #%(order)s на покупку {amount} по {price}", + "{account} разместил ордер %(order)s на покупку {amount} по {price}", "limit_order_cancel": "{account} отменил ордер #%(order)s", "limit_order_sell": - "{account} разместил ордер #%(order)s на продажу {amount} по {price}", + "{account} разместил ордер %(order)s на продажу {amount} по {price}", "no_recent": "Нет недавних транзакций", "override_transfer": "{issuer} перевел {amount} с {from} на {to}", "pending": "обрабатывается ещё %(blocks)s блоков", @@ -1380,11 +1381,11 @@ "feed_producer": "Обновить поставщиков котировок для актива {asset} используя аккаунт {account}", "limit_order_buy": - "Разместить ордер на покупку {amount} по {price} для {account}", + "Разместить ордер на покупку {amount} за {price} для {account}", "limit_order_create": "Разместить ордер на покупку %(buy_amount)s за %(sell_amount)s для %(account)s", "limit_order_sell": - "Разместить ордер на продажу {amount} по {price} для {account}", + "Разместить ордер на продажу {amount} за {price} для {account}", "override_transfer": "Перевести {amount} от {from} к {to} по поручению {issuer}", "proposals": "Предложения", @@ -1471,7 +1472,7 @@ "Вы уверены, что хотите удалить %(name)s из Вашего списка доступных узлов?", "confirm_yes": "Всегда", "connection_error": - "Не удается подключиться к узлу API %(url)s, возврат к известным рабочим узлам", + "Не удается подключиться к узлу API %(url)s, возврат к известным рабочим узлам. Ошибка: %(error)s", "darkTheme": "Темная тема", "delete_select": "Выберите локальный кошелек для удаления", "enable_wallet": "Переключиться на модель кошелька", @@ -1503,7 +1504,7 @@ "passwordLogin": "Режим входа", "password_text": "Поменяйте пароль.", "ping": "Проверить Узлы", - "pinging": "Pinging ...", + "pinging": "Отслеживается...", "remove": "Удалить", "remove_api": "Удалить API", "remove_ws": "Удалить WebSocket API", @@ -1581,14 +1582,15 @@ "hide_asset": "Нажмите здесь, чтобы скрыть актив из этого списка.", "latest_price": "Это самая актуальная цена для этого рынка.", "login": - "Кошелек BitShares не предоставляет возможности использования традиционного логина, но вместо этого просто открывает и закрывает кошелек, который хранится локально только в Вашем браузере.

    Каждый раз, как Вы выходите из кошелька, он закрывается и Вы выходите из аккаунта.", + "Кошелек %(wallet_name)s не предоставляет возможности использования традиционного логина, но вместо этого просто открывает и закрывает кошелек, который хранится локально только в Вашем браузере.

    Каждый раз, как Вы выходите из кошелька, он закрывается, и Вы выходите из аккаунта.", "margin_price": "Это максимальная цена, которую может быть вынуждена заплатить позиция с затребованным дополнительным обеспечением. Также она называется Squeeze Price.", "market_fee": "Владелец %(asset)s назначил для ордеров на покупку рыночную комиссию в размере %(percent)s%%. Эта комиссия будет вычтена из суммы, полученной Вами при выполнении ордера, в момент же размещения ордера она не взимается.", "memo_tip": "В поле примечания Вы можете включить любое сообщение. Примечание необязательно, но обычно необходимо для перевода на биржи.", - "no_groups_available": "No groupings available using this API server", + "no_groups_available": + "На используемом API сервере нет доступных групп", "no_price": "Для этого актива нет доступной недавней цены, которая может быть использована для оценки его стоимости.", "over_limit": @@ -1806,7 +1808,7 @@ "from": "От", "header": "Детали транзакции", "header_subheader": - "Переводы используются для отправки средств другим владельцам аккаунтов BitShares", + "Переводы используются для отправки средств другим владельцам аккаунтов %(wallet_name)s", "memo": "Примечание", "memo_unlock": "Разблокируйте Ваш кошелек/аккаунт, чтобы увидеть это примечание", @@ -1869,7 +1871,7 @@ "Нажав на кнопку ниже, Вы создадите резервную копию с расширением .bin. Этот файл зашифрован паролем Вашего кошелька и содержит все приватные ключи Вашего аккаунта. Он может быть использован для восстановления Вашего кошелька или его перемещения на другой компьютер/браузер.", "backup_login": "Резервное копирование и вход в систему", "backup_new_account": - "Поздравляем, Вы только что создали новый аккаунт в блокчейне BitShares! Настоятельно рекомендуем Вам сразу же создать резервную копию кошелька. Без резервной копии восстановить Ваш аккаунт в случае повреждения компьютера будет невозможно.", + "Поздравляем, Вы только что создали новый аккаунт в %(wallet_name)s, работающем на базе блокчейна BitShares! Настоятельно рекомендуем Вам сразу же создать резервную копию кошелька. Без резервной копии восстановить Ваш аккаунт в случае повреждения компьютера будет невозможно.", "backup_warning": "Резервная копия файлов ваших закрытых ключей еще не создавалась. В целях безопасности мы рекомендуем пользователям не входить в систему без предварительно созданной резервной копии своих закрытых ключей.", "balance_claim_lookup": "Просмотреть балансы", @@ -1921,7 +1923,7 @@ "create_password": "Создать новый аккаунт используя пароль", "create_success": "Вы успешно создали локальный кошелек", "create_text": - "Локальный кошелек BitShares хранится в Вашем браузере, а не в облаке. Кошелек может содержать несколько аккаунтов, а также может легко переноситься между браузерами и компьютерами с помощью резервной копии.", + "Локальный кошелек %(wallet_name)s хранится в Вашем браузере, а не в облаке. Кошелек может содержать несколько аккаунтов, а также может легко переноситься между браузерами и компьютерами с помощью резервной копии.", "create_w_a": "Создать локальный кошелек, содержащий аккаунт", "create_wallet": "Создать новый локальный кошелек", "create_wallet_backup": "Создать новый кошелек из резервной копии", @@ -1948,12 +1950,12 @@ "generated": "Сгенерированный пароль", "go_get_started": "Начало работы", "has_wallet": - "Как только Вы создадите Ваш первый аккаунт BitShares, будет автоматически создан локальный кошелек BitShares, который будет храниться в Вашем браузере! Этот локальный кошелек зашифрован Вашим паролем и содержит все закрытые ключи, принадлежащие Вашим аккаунтам. Не забудьте создать резервную копию этого кошелька!", + "Как только Вы создадите Ваш первый аккаунт %(wallet_name)s, будет автоматически создан локальный кошелек %(wallet_name)s, который будет храниться в Вашем браузере. Этот локальный кошелек зашифрован Вашим паролем и содержит все закрытые ключи, принадлежащие Вашим аккаунтам. Не забудьте создать резервную копию этого кошелька!", "import_20_notice1": "Сначала импортируйте Вашу резервную копию BTS 2.0+", "import_20_notice2": "(если такая имеется)", "import_backup": - "Импортировать резервную копию BitShares 2.0 (.bin файл)", + "Импортировать резервную копию %(wallet_name)s 2.0 (.bin файл)", "import_backup_choose": "Пожалуйста, выберите Вашу резервную копию в окне ниже. Это абсолютно безопасно, так как файл копии никуда не загружается и никогда не покинет Ваш браузер.", "import_balance": "Импортировать баланс(ы)", From 5807e671c28e3d1fc0b458c5ad9721ca7e73fe0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Sat, 21 Jul 2018 16:29:48 +0200 Subject: [PATCH 17/69] #1672: Remove API nodes without support for orders API (#1708) * for #1672 Signed-off-by: Stefan Schiessl * readded {url: "wss://blockzms.xyz/ws", location: "USA"} due to update Signed-off-by: Stefan Schiessl --- app/api/apiConfig.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index e59751a7f4..b038afa86e 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -84,8 +84,6 @@ export const settingsAPIs = { {url: "wss://bit.btsabc.org/ws", location: "Hong Kong"}, {url: "wss://node.btscharts.com/ws", location: "Hong Kong"}, {url: "wss://japan.bitshares.apasia.tech/ws", location: "Tokyo, Japan"}, - {url: "wss://bitshares.dacplay.org/ws", location: "Hangzhou, China"}, - {url: "wss://bitshares-api.wancloud.io/ws", location: "China"}, {url: "wss://openledger.hk/ws", location: "Hong Kong"}, {url: "wss://bitshares.crypto.fans/ws", location: "Munich, Germany"}, {url: "wss://ws.gdex.io", location: "Japan"}, @@ -100,6 +98,7 @@ export const settingsAPIs = { {url: "wss://node.market.rudex.org", location: "Germany"}, {url: "wss://api.bitsharesdex.com/ws", location: "Missouri, USA"}, {url: "wss://api.fr.bitsharesdex.com/ws", location: "France"}, + {url: "wss://blockzms.xyz/ws", location: "USA"}, { url: "wss://eu.nodes.bitshares.ws", location: "Central Europe - BitShares Infrastructure Program" @@ -127,11 +126,9 @@ export const settingsAPIs = { {url: "wss://api.btsgo.net/ws", location: "Singapore"}, {url: "wss://bts.proxyhosts.info/wss", location: "Germany"}, {url: "wss://bts.open.icowallet.net/ws", location: "Hangzhou, China"}, - {url: "wss://blockzms.xyz/ws", location: "USA"}, {url: "wss://crazybit.online", location: "China"}, {url: "wss://freedom.bts123.cc:15138/", location: "China"}, {url: "wss://bitshares.bts123.cc:15138/", location: "China"}, - {url: "wss://api.bts.ai/", location: "Beijing, China"}, {url: "wss://ws.hellobts.com/", location: "Japan"}, {url: "wss://bitshares.cyberit.io/", location: "Hong Kong"}, {url: "wss://bts-seoul.clockwork.gr/", location: "Seoul, Korea"}, From fee3e3110c2896314b11f898db4dbab9ca19ef71 Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Sat, 21 Jul 2018 20:35:04 +0200 Subject: [PATCH 18/69] Fix #1575 - Adding UI for Target CR on Modal (#1713) * Adding UI for Target CR on Modal * Target CR Modal - Fixes * Add Target CR to Asset Maring Positions --- app/assets/locales/locale-en.json | 5 + app/components/Blockchain/Asset.jsx | 6 + app/components/Modal/BorrowModal.jsx | 186 +++++++++++++++++++++++---- 3 files changed, 173 insertions(+), 24 deletions(-) diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index ac10301992..71ca28e034 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -430,6 +430,9 @@ "call_limit": "Market Call Limit", "close": "Close position", "coll_ratio": "Ratio", + "coll_ratio_target": "Target Ratio", + "target_collateral_ratio": "Target Collateral Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Your collateral ratio is below %(mr)s which is not allowed.", @@ -1580,6 +1583,8 @@ "sync_no": "The current node is out of sync with the blockchain, try switching to another one", "sync_yes": "The current node is in sync with the blockchain", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Click here to make a transfer, or to deposit/withdraw those assets that support it.", "update_position": diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index e2cfa81e6b..fb6a2357f2 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -1022,6 +1022,9 @@ class Asset extends React.Component { ) : null} + + + + + {!!c.order.target_collateral_ratio ? (c.order.target_collateral_ratio / 1000).toFixed(3) : "-"} + {c.getRatio().toFixed(3)} diff --git a/app/components/Modal/BorrowModal.jsx b/app/components/Modal/BorrowModal.jsx index 83060dd7ce..7c06be8c09 100755 --- a/app/components/Modal/BorrowModal.jsx +++ b/app/components/Modal/BorrowModal.jsx @@ -58,15 +58,23 @@ class BorrowModalContent extends React.Component { currentPosition.collateral, props.backing_asset ); + + let target_collateral_ratio = !isNaN(currentPosition.target_collateral_ratio) + ? currentPosition.target_collateral_ratio / 100 + : 0; + return { short_amount: debt ? debt.toString() : null, collateral: collateral ? collateral.toString() : null, collateral_ratio: this._getCollateralRatio(debt, collateral), + target_collateral_ratio: target_collateral_ratio, errors: this._getInitialErrors(), isValid: false, + useTargetCollateral: target_collateral_ratio > 0 ? true : false, original_position: { debt: debt, - collateral: collateral + collateral: collateral, + target_collateral_ratio: target_collateral_ratio } }; } else { @@ -74,8 +82,10 @@ class BorrowModalContent extends React.Component { short_amount: 0, collateral: 0, collateral_ratio: this._getInitialCollateralRatio(props), + target_collateral_ratio: 0, errors: this._getInitialErrors(), isValid: false, + useTargetCollateral: false, original_position: { debt: 0, collateral: 0 @@ -197,6 +207,22 @@ class BorrowModalContent extends React.Component { this._setUpdatedPosition(newState); } + _onTargetRatioChange(e) { + let target = e.target; + + // Ensure input is valid + const regexp_numeral = new RegExp(/[[:digit:]]/); + if (!regexp_numeral.test(target.value)) { + target.value = target.value.replace(/[^0-9.]/g, ""); + } + + let ratio = target.value; + + this.setState({ + target_collateral_ratio: ratio + }); + } + _onRatioChange(e) { let feed_price = this._getFeedPrice(); let target = e.target; @@ -405,30 +431,69 @@ class BorrowModalContent extends React.Component { ); let currentPosition = this._getCurrentPosition(this.props); + let isTCR = typeof(this.state.target_collateral_ratio) !== "undefined" + && this.state.target_collateral_ratio > 0 + && this.state.useTargetCollateral + ? true + : false; + + let extensionsProp = false; + + if(isTCR) { + extensionsProp = { target_collateral_ratio: parseInt(this.state.target_collateral_ratio * 100, 10) }; + } + var tr = WalletApi.new_transaction(); - tr.add_type_operation("call_order_update", { - fee: { - amount: 0, - asset_id: 0 - }, - funding_account: this.props.account.get("id"), - delta_collateral: { - amount: parseInt( - this.state.collateral * backingPrecision - - currentPosition.collateral, - 10 - ), - asset_id: this.props.backing_asset.get("id") - }, - delta_debt: { - amount: parseInt( - this.state.short_amount * quotePrecision - - currentPosition.debt, - 10 - ), - asset_id: this.props.quote_asset.get("id") - } - }); + if(extensionsProp) { + tr.add_type_operation("call_order_update", { + fee: { + amount: 0, + asset_id: 0 + }, + funding_account: this.props.account.get("id"), + delta_collateral: { + amount: parseInt( + this.state.collateral * backingPrecision - + currentPosition.collateral, + 10 + ), + asset_id: this.props.backing_asset.get("id") + }, + delta_debt: { + amount: parseInt( + this.state.short_amount * quotePrecision - + currentPosition.debt, + 10 + ), + asset_id: this.props.quote_asset.get("id") + }, + extensions: extensionsProp + }); + } else { + tr.add_type_operation("call_order_update", { + fee: { + amount: 0, + asset_id: 0 + }, + funding_account: this.props.account.get("id"), + delta_collateral: { + amount: parseInt( + this.state.collateral * backingPrecision - + currentPosition.collateral, + 10 + ), + asset_id: this.props.backing_asset.get("id") + }, + delta_debt: { + amount: parseInt( + this.state.short_amount * quotePrecision - + currentPosition.debt, + 10 + ), + asset_id: this.props.quote_asset.get("id") + }, + }); + } WalletDb.process_transaction(tr, null, true).catch(err => { // console.log("unlock failed:", err); }); @@ -504,6 +569,12 @@ class BorrowModalContent extends React.Component { return props.quote_asset.getIn(["bitasset", "is_prediction_market"]); } + _setUseTargetCollateral() { + this.setState({ + useTargetCollateral: !this.state.useTargetCollateral + }); + } + render() { let { quote_asset, @@ -515,6 +586,7 @@ class BorrowModalContent extends React.Component { short_amount, collateral, collateral_ratio, + target_collateral_ratio, errors, original_position } = this.state; @@ -616,6 +688,66 @@ class BorrowModalContent extends React.Component { ); + let updateTargetCollateral = ( + + +
    + +    + +
    + {this.state.useTargetCollateral ? + + + + + : null} +
    + ); + let feed_price = this._getFeedPrice(); let maintenanceRatio = this._getMaintenanceRatio(); @@ -899,6 +1031,12 @@ class BorrowModalContent extends React.Component {
    ) : null}
    +
    + {updateTargetCollateral} +
    ) : null}
    From 50f0d1afd7ab26ca8f45fef7329d4c912212b7ca Mon Sep 17 00:00:00 2001 From: Ruslan Salikhov Date: Wed, 25 Jul 2018 16:55:04 +0500 Subject: [PATCH 19/69] Fix gateway enabling (#1722) --- app/branding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/branding.js b/app/branding.js index a78bd692fe..5e8941cfbb 100644 --- a/app/branding.js +++ b/app/branding.js @@ -261,7 +261,7 @@ export function getAssetHideNamespaces() { * @returns {boolean} */ export function allowedGateway(gateway) { - return gateway in ["OPEN", "RUDEX", "WIN", "BRIDGE", "GDEX"]; + return ["OPEN", "RUDEX", "WIN", "BRIDGE", "GDEX"].indexOf(gateway) >= 0; } export function getSupportedLanguages() { From 51450bd028de9343482e94da445f6618802e5f4d Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Wed, 25 Jul 2018 13:56:19 +0200 Subject: [PATCH 20/69] #1575: Fixes for Target CR (#1725) - Adds Target CR to TX details - Fixes checkbox not working properly on modal --- app/assets/locales/locale-en.json | 1 + app/assets/stylesheets/components/_modal.scss | 8 ++ app/components/Blockchain/Transaction.jsx | 15 ++ app/components/Modal/BorrowModal.jsx | 132 ++++++++++-------- 4 files changed, 94 insertions(+), 62 deletions(-) diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 71ca28e034..1caf861e0b 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -1620,6 +1620,7 @@ "coll_of": "with collateral of", "coll_ratio": "Initial collateral ratio", "collateral": "Collateral", + "collateral_target": "Target Collateral", "committee_member_create": "Created the committee member", "confirm": "Please confirm the transaction", "create_key": "Created a public key", diff --git a/app/assets/stylesheets/components/_modal.scss b/app/assets/stylesheets/components/_modal.scss index 13a0d4dc93..e3383003f7 100644 --- a/app/assets/stylesheets/components/_modal.scss +++ b/app/assets/stylesheets/components/_modal.scss @@ -134,3 +134,11 @@ #simple_bridge_modal_ask label { text-transform: none !important; } + +// Ant Overrides +label.ant-checkbox-wrapper { + > span { + text-transform: none; + } +} + \ No newline at end of file diff --git a/app/components/Blockchain/Transaction.jsx b/app/components/Blockchain/Transaction.jsx index b45bba7c8e..10ba3dd61c 100644 --- a/app/components/Blockchain/Transaction.jsx +++ b/app/components/Blockchain/Transaction.jsx @@ -439,6 +439,21 @@ class Transaction extends React.Component { ); + {!!op[1].extensions && !!op[1].extensions.target_collateral_ratio ? + rows.push( + + + + + + {op[1].extensions.target_collateral_ratio / 100} + + + ) + : null} break; case "key_create": diff --git a/app/components/Modal/BorrowModal.jsx b/app/components/Modal/BorrowModal.jsx index 7c06be8c09..468eac887d 100755 --- a/app/components/Modal/BorrowModal.jsx +++ b/app/components/Modal/BorrowModal.jsx @@ -21,6 +21,7 @@ import Immutable from "immutable"; import {ChainStore} from "bitsharesjs"; import {List} from "immutable"; import Icon from "../Icon/Icon"; +import {Checkbox} from "bitshares-ui-style-guide"; /** * Given an account and an asset id, render a modal allowing modification of a margin position for that asset @@ -588,7 +589,8 @@ class BorrowModalContent extends React.Component { collateral_ratio, target_collateral_ratio, errors, - original_position + original_position, + useTargetCollateral } = this.state; let quotePrecision = utils.get_asset_precision( this.props.quote_asset.get("precision") @@ -688,66 +690,6 @@ class BorrowModalContent extends React.Component { ); - let updateTargetCollateral = ( - - -
    - -    - -
    - {this.state.useTargetCollateral ? - - - - - : null} -
    - ); - let feed_price = this._getFeedPrice(); let maintenanceRatio = this._getMaintenanceRatio(); @@ -1035,7 +977,73 @@ class BorrowModalContent extends React.Component { className={"form-group"} style={{marginBottom: "3.5rem"}} > - {updateTargetCollateral} + + + {useTargetCollateral ? + +
    + + + +
    + + + + +
    + : +
    + + + +
    + } +
    ) : null} From 89486ccbedf20fbcda1d9675f275ab894023858d Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Wed, 25 Jul 2018 14:25:15 +0200 Subject: [PATCH 21/69] Fix #1704: Theme Issues on Asset Explorer (#1717) - Outline buttons color issues solved --- app/assets/stylesheets/themes/_theme-template.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/themes/_theme-template.scss b/app/assets/stylesheets/themes/_theme-template.scss index 488868850c..8b35b508f1 100644 --- a/app/assets/stylesheets/themes/_theme-template.scss +++ b/app/assets/stylesheets/themes/_theme-template.scss @@ -417,6 +417,9 @@ background-color: lighten($button-bg-color, 4%) !important; } &.outline { + span { + color: $primary-text-color !important; + } color: $secondary-text-color; border-color: $secondary-text-color; &:hover { From 23e52977b022f462f0dcd16fde2bda4f0d0be11a Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Wed, 25 Jul 2018 15:41:53 +0200 Subject: [PATCH 22/69] Fix #1667 - Dashboard Column Reordering (#1718) * Dashboard Colum reordering Dashboard Table right/left spacing * Dashboard table spacing --- .../stylesheets/components/_account.scss | 4 + app/components/Exchange/MyOpenOrders.jsx | 81 +++++++++---------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/app/assets/stylesheets/components/_account.scss b/app/assets/stylesheets/components/_account.scss index 41a761e10a..7c888043ed 100755 --- a/app/assets/stylesheets/components/_account.scss +++ b/app/assets/stylesheets/components/_account.scss @@ -334,6 +334,10 @@ table.table.dashboard-table { > tbody > tr > td:first-of-type { padding-left: 1.5rem; } + > thead > tr > th:last-of-type, + > tbody > tr > td:last-of-type { + padding-right: 1.5rem; + } > thead > tr > th { @include RobotoMedium; font-size: 0.875rem; diff --git a/app/components/Exchange/MyOpenOrders.jsx b/app/components/Exchange/MyOpenOrders.jsx index 7cf140279b..18eed11927 100644 --- a/app/components/Exchange/MyOpenOrders.jsx +++ b/app/components/Exchange/MyOpenOrders.jsx @@ -67,6 +67,14 @@ class TableHeader extends React.Component { ) : ( + {isMyAccount ? ( + + + + ) : null} + + + @@ -82,15 +90,6 @@ class TableHeader extends React.Component { - {/* */} - - - - {isMyAccount ? ( - - - - ) : null} ); @@ -198,6 +197,35 @@ class OrderRow extends React.Component { ) : ( + {isMyAccount ? ( + + {isCall ? null : ( + + + + )} + + ) : null} + + + + + #{order.id.substring(4)} {isBid ? ( @@ -305,41 +333,6 @@ class OrderRow extends React.Component { />{" "} - {/* - {isCall ? null : } - */} - - - - - - {isMyAccount ? ( - - {isCall ? null : ( - - - - )} - - ) : null} ); } From a65e856a647c2bc0e292b3b90b654afc9d89660b Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Wed, 25 Jul 2018 15:42:41 +0200 Subject: [PATCH 23/69] Fix #1688 - Add Trading link to margin table (#1719) * Add Trading link to margin table * Margin Dashboard - Set Market link to its own column --- app/components/Account/MarginPositions.jsx | 29 ++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/app/components/Account/MarginPositions.jsx b/app/components/Account/MarginPositions.jsx index 66eab53af4..b4923ac24d 100644 --- a/app/components/Account/MarginPositions.jsx +++ b/app/components/Account/MarginPositions.jsx @@ -293,7 +293,18 @@ class MarginPosition extends React.Component { /> {/* / */} - + + + + +
    {/* / */} - + + + + +
    + + + From b0283513e6b2e33edc7b2de87630b2b1ce2739ac Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Wed, 25 Jul 2018 15:43:22 +0200 Subject: [PATCH 24/69] Fix #1628: Add checker for inputs on withdrawal (#1721) --- .../blocktrades/BlockTradesBridgeDepositRequest.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx b/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx index 777365b179..2aaa45ac47 100644 --- a/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx +++ b/app/components/DepositWithdraw/blocktrades/BlockTradesBridgeDepositRequest.jsx @@ -336,6 +336,7 @@ class ButtonWithdraw extends React.Component { ) ) { if ( + this.props.amount_to_withdraw && !(this.props.amount_to_withdraw.indexOf(" ") >= 0) && !isNaN(this.props.amount_to_withdraw) && this.props.amount_to_withdraw > 0 && From d5e648136543a466a1b254d60530aeec3faada1d Mon Sep 17 00:00:00 2001 From: Startail the 'Coon Date: Wed, 25 Jul 2018 20:49:36 +0200 Subject: [PATCH 25/69] Fix #1727: Target CR Delimiter (#1728) --- app/components/Blockchain/Transaction.jsx | 2 +- app/components/Modal/BorrowModal.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/Blockchain/Transaction.jsx b/app/components/Blockchain/Transaction.jsx index 10ba3dd61c..ddccddf988 100644 --- a/app/components/Blockchain/Transaction.jsx +++ b/app/components/Blockchain/Transaction.jsx @@ -449,7 +449,7 @@ class Transaction extends React.Component { /> - {op[1].extensions.target_collateral_ratio / 100} + {op[1].extensions.target_collateral_ratio / 1000} ) diff --git a/app/components/Modal/BorrowModal.jsx b/app/components/Modal/BorrowModal.jsx index 468eac887d..1a21897784 100755 --- a/app/components/Modal/BorrowModal.jsx +++ b/app/components/Modal/BorrowModal.jsx @@ -61,7 +61,7 @@ class BorrowModalContent extends React.Component { ); let target_collateral_ratio = !isNaN(currentPosition.target_collateral_ratio) - ? currentPosition.target_collateral_ratio / 100 + ? currentPosition.target_collateral_ratio / 1000 : 0; return { @@ -441,7 +441,7 @@ class BorrowModalContent extends React.Component { let extensionsProp = false; if(isTCR) { - extensionsProp = { target_collateral_ratio: parseInt(this.state.target_collateral_ratio * 100, 10) }; + extensionsProp = { target_collateral_ratio: parseInt(this.state.target_collateral_ratio * 1000, 10) }; } var tr = WalletApi.new_transaction(); From 9dfe05738145f4335700c38e401202e08b4531cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Thu, 26 Jul 2018 10:05:13 +0200 Subject: [PATCH 26/69] #1521 #1672 Fix #1462: Better Node Management, Orders Api and Refactoring (#1726) * prepatory work for #1521 and #1672 - refactoring of SettingsStore and AccessSettings - prepare routerTransitioner to support a more sophistiaced node dictionary Signed-off-by: Stefan Schiessl * for #1521 #1672 - second wholesome refactoring of AccessSettings. ApiNode has all the knowledge itself now - refactored SettingsStore. Next step: eliminate bug that defaults are not overwritten Signed-off-by: Stefan Schiessl * continued refactoring of SettingsStore and node management in AccessSettings Signed-off-by: Stefan Schiessl * - final round of AccessSettings refactor and SettingsStore Signed-off-by: Stefan Schiessl * add more detail in node selection avoid duplicate saving in settingsstore activeNode does not be mainteined in local storage Signed-off-by: Stefan Schiessl * - added operator updates till today - new modal: ChoiceModal * some more docs Signed-off-by: Stefan Schiessl * Fix SettingsStore init for new visitors * Fix backwards compatibility enable check * Fix the BrowserNotifications error when switching nodes * Add text explaining how to modify/remove personal nodes when active * Remove some logs --- app/api/apiConfig.js | 100 ++- app/assets/locales/locale-de.json | 15 + app/assets/locales/locale-en.json | 15 +- app/assets/locales/locale-es.json | 15 + app/assets/locales/locale-fr.json | 15 + app/assets/locales/locale-it.json | 15 + app/assets/locales/locale-ja.json | 15 + app/assets/locales/locale-ko.json | 15 + app/assets/locales/locale-ru.json | 15 + app/assets/locales/locale-tr.json | 15 + app/assets/locales/locale-zh.json | 15 + app/assets/stylesheets/components/_modal.scss | 1 - .../stylesheets/components/_settings.scss | 10 +- app/branding.js | 2 +- app/components/Account/MarginPositions.jsx | 8 +- app/components/Blockchain/Asset.jsx | 6 +- app/components/Blockchain/Transaction.jsx | 13 +- .../BrowserNotificationsContainer.jsx | 6 +- app/components/Layout/Footer.jsx | 118 +-- app/components/Modal/BorrowModal.jsx | 81 +- app/components/Modal/ChoiceModal.js | 84 ++ app/components/Settings/AccessSettings.jsx | 729 ++++++++++-------- app/routerTransition.js | 194 +++-- app/stores/SettingsStore.js | 391 ++++++++-- 24 files changed, 1295 insertions(+), 598 deletions(-) create mode 100644 app/components/Modal/ChoiceModal.js diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index b038afa86e..06b0fdbf59 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -67,25 +67,82 @@ export const gdexAPIs = { WITHDRAW_RULE: "/gateway/withdraw/rule" }; +export const nodeRegions = [ + // region of the node follows roughly https://en.wikipedia.org/wiki/Subregion#/media/File:United_Nations_geographical_subregions.png + "Northern Europe", + "Western Europe", + "Southern Europe", + "Eastern Europe", + "Northern Asia", + "Western Asia", + "Southern Asia", + "Eastern Asia", + "Central Asia", + "Southeastern Asia", + "Australia", + "New Zealand", + "Melanesia", + "Polynesia", + "Micronesia", + "Northern Africa", + "Western Africa", + "Middle Africa", + "Eastern Africa", + "Southern Africa", + "Northern America", + "Central America", + "Caribbean", + "South America" +]; + export const settingsAPIs = { + // If you want a location to be translated, add the translation to settings in locale-xx.js + // and use an object {translate: key} in WS_NODE_LIST DEFAULT_WS_NODE: "wss://fake.automatic-selection.com", WS_NODE_LIST: [ { url: "wss://fake.automatic-selection.com", location: {translate: "settings.api_closest"} }, - {url: "ws://127.0.0.1:8090", location: "Locally hosted"}, + { + url: "ws://127.0.0.1:8090", + location: "Locally hosted" + }, { url: "wss://bitshares.openledger.info/ws", - location: "Nuremberg, Germany" + location: "Nuremberg", + region: "Western Europe", // stick to the regions that are available in nodeRegions + country: "Germany", + operator: "OpenLedger" + }, + { + url: "wss://eu.openledger.info/ws", + location: "Berlin", + region: "Western Europe", // stick to the regions that are available in nodeRegions + country: "Germany", + operator: "OpenLedger" + }, + { + url: "wss://bitshares.nu/ws", + location: "Stockholm", + region: "Northern Europe", + country: "Sweden" + }, + { + url: "wss://bit.btsabc.org/ws", + location: "Hong Kong" }, - {url: "wss://eu.openledger.info/ws", location: "Berlin, Germany"}, - {url: "wss://bitshares.nu/ws", location: "Stockholm, Sweden"}, - {url: "wss://bit.btsabc.org/ws", location: "Hong Kong"}, {url: "wss://node.btscharts.com/ws", location: "Hong Kong"}, {url: "wss://japan.bitshares.apasia.tech/ws", location: "Tokyo, Japan"}, {url: "wss://openledger.hk/ws", location: "Hong Kong"}, - {url: "wss://bitshares.crypto.fans/ws", location: "Munich, Germany"}, + { + url: "wss://bitshares.crypto.fans/ws", + region: "Western Europe", + country: "Germany", + location: "Munich", + operator: "Witness: sc-ol", + contact: "telegram:startail" + }, {url: "wss://ws.gdex.io", location: "Japan"}, {url: "wss://ws.gdex.top", location: "China"}, {url: "wss://dex.rnglab.org", location: "Netherlands"}, @@ -101,18 +158,32 @@ export const settingsAPIs = { {url: "wss://blockzms.xyz/ws", location: "USA"}, { url: "wss://eu.nodes.bitshares.ws", - location: "Central Europe - BitShares Infrastructure Program" + region: "Western Europe", + country: "Germany", + operator: "Infrastructure Worker", + contact: "email:info@blockchainprojectsbv.com" }, { url: "wss://us.nodes.bitshares.ws", - location: "U.S. West Coast - BitShares Infrastructure Program" + region: "North America", + country: "U.S.A.", + operator: "Infrastructure Worker" }, { url: "wss://sg.nodes.bitshares.ws", - location: "Singapore - BitShares Infrastructure Program" + region: "Southeastern Asia", + country: "Singapore", + operator: "Infrastructure Worker" }, {url: "wss://ws.winex.pro", location: "Singapore"}, - {url: "wss://api.bts.mobi/ws", location: "VA, USA"}, + { + url: "wss://api.bts.mobi/ws", + region: "Northern America", + country: "USA", + location: "Virginia", + operator: "Witness: in.abit", + contact: "telegram:abitmore" + }, { url: "wss://api.btsxchng.com", location: @@ -131,7 +202,14 @@ export const settingsAPIs = { {url: "wss://bitshares.bts123.cc:15138/", location: "China"}, {url: "wss://ws.hellobts.com/", location: "Japan"}, {url: "wss://bitshares.cyberit.io/", location: "Hong Kong"}, - {url: "wss://bts-seoul.clockwork.gr/", location: "Seoul, Korea"}, + { + url: "wss://bts-seoul.clockwork.gr", + region: "Southeastern Asia", + country: "Korea", + location: "Seoul", + operator: "Witness: clockwork", + contact: "telegram:clockworkgr" + }, {url: "wss://bts.to0l.cn:4443/ws", location: "China"}, {url: "wss://btsfullnode.bangzi.info/ws", location: "Germany"}, // Testnet diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index 91bc70b569..c59e6ef4cb 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -418,6 +418,8 @@ "browser_text": "Ihr Browser ist unzureichend mit der BitShares-Wallet getestet worden. Wir empfehlen Ihnen, eine Sicherung ihrer Geldbörse durchzuführen und diese in den Chrome Browser zu importieren. Nutzen Sie Ihren Browser auf eigene Gefahr!", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "verbunden", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -433,6 +435,8 @@ "call_limit": "Markt Call Limit", "close": "Position schlißen", "coll_ratio": "Kollateral-Ratio", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Kollateral-Ratio unter Aufrechterhaltungslevel", "below_info": @@ -449,6 +453,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "Kein gültiger Feed-Preis für %(asset_symbol)s", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "Kollateral Position für %(asset_symbol)s", "update": "Aktualisieren", "use_max": "Use Max" @@ -461,6 +466,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1480,6 +1486,8 @@ "password": "Password", "passwordLogin": "Login using the account model", "password_text": "Change your password.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "Remove", @@ -1498,7 +1506,11 @@ "show": "Show", "showAssetPercent": "Show asset percentages on the account page", "showSettles": "Settlements in der Depth-Chart anzeigen", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Theme", "unit": "Bevorzugte Rechnungseinheit", "valid_node_url": "Node URL must begin with ws:// or wss://", @@ -1580,6 +1592,8 @@ "sync_no": "The current node is out of sync with the blockchain, try switching to another one", "sync_yes": "The current node is in sync with the blockchain", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Click here to make a transfer, or to deposit/withdraw those assets that support it.", "update_position": @@ -1616,6 +1630,7 @@ "coll_of": "mit einer Sicherheit bestehend aus", "coll_ratio": "Anfängliche Sicherheit (Verhältnis)", "collateral": "Sicherheit/Pfand", + "collateral_target": "Target Collateral", "committee_member_create": "Komitee-Mitglied erstellen", "confirm": "Bitte bestätigen Sie die Transaktion", "create_key": "Ein öffentlicher Schlüssel wurde erzeugt", diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 1caf861e0b..e12d065c78 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -412,7 +412,7 @@ "browser": "Unsupported browser", "browser_text": "The Browser you are using has not been fully tested to support the %(wallet_name)s Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", - "check_latency": "Running latency checks ...", + "check_latency": "Running latency checks...", "check_latency_feedback": "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Connected", @@ -431,7 +431,6 @@ "close": "Close position", "coll_ratio": "Ratio", "coll_ratio_target": "Target Ratio", - "target_collateral_ratio": "Target Collateral Ratio", "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": @@ -450,6 +449,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "No valid feeds for %(asset_symbol)s", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s Margin", "update": "Update", "use_max": "Use Max" @@ -462,7 +462,8 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", - "manual_reconnect": "Reconnect now", + "manual_ping": "Go to ping nodes", + "manual_reconnect": "Try reconnecting now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", "title_out_of_sync": "Connection out of sync", @@ -1419,7 +1420,7 @@ "always_confirm": "Always ask for confirmation", "apiServer": "Full node API server", "api_closest": "Choose closest automatically", - "automatic": "Automatically select node (%(totalNodes)s available)", + "automatic": "Automatically select node (%(totalNodes)s listed)", "automatic_short": "Automatic Switching", "available_nodes": "Available", "backup": "Backup", @@ -1483,6 +1484,8 @@ "password": "Password", "passwordLogin": "Login mode", "password_text": "Change your password.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "Remove", @@ -1501,7 +1504,11 @@ "show": "Show", "showAssetPercent": "Show asset percentages on the account page", "showSettles": "Show settle orders in depth chart", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Theme", "unit": "Preferred unit of account", "valid_node_url": "Node URL must begin with ws:// or wss://", diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index d9dd29c0c3..a8f64aec70 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -426,6 +426,8 @@ "browser_text": "El navegador que está utilizando no se ha probado completamente para admitir la billetera BitShares. Le recomendamos encarecidamente que haga una copia de seguridad de su monedero local e importarlo utilizando el navegador Chrome hasta que hayamos tenido más tiempo para probar completamente el navegador de su elección. Úselo bajo su propio riesgo.", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Conectado", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -441,6 +443,8 @@ "call_limit": "Mercado llamada a limite", "close": "Cerrar la posición", "coll_ratio": "Proporción", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Su colateral está por debajo %(mr)s y no está permitido.", "below_info": @@ -457,6 +461,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "No hay feeds válidos para %(asset_symbol)s", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s Margen", "update": "Actualizar", "use_max": "Use Max" @@ -469,6 +474,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1499,6 +1505,8 @@ "password": "Contraseña", "passwordLogin": "Modo de acceso", "password_text": "cambia tu contraseña.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "retirar", @@ -1522,7 +1530,11 @@ "Mostrar porcentajes de activos en la página de la cuenta", "showSettles": "Mostrar órdenes de liquidación en el gráfico de profundidad", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Tema", "unit": "Unidad preferida para esta cuenta", "valid_node_url": "La URL del nodo debe comenzar con ws:// or wss://", @@ -1608,6 +1620,8 @@ "sync_no": "El nodo actual no está sincronizado con la cadena de bloques, intente cambiar a otro", "sync_yes": "El nodo actual está sincronizado con la cadena de bloques", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": " Haga clic aquí para hacer una transferencia, o para depositar / retirar aquellos activos que lo soportan.", "update_position": @@ -1643,6 +1657,7 @@ "coll_of": "con un colateral de", "coll_ratio": "Relación colateral inicial", "collateral": "Colateral", + "collateral_target": "Target Collateral", "committee_member_create": "Miembro del Comité creado", "confirm": "Por favor confirme la transacción", "create_key": "Llave pública creada", diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index ebb4bf14b5..9900d737b9 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -413,6 +413,8 @@ "browser_text": "The Browser you are using has not been fully tested to support the BitShares Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Connected", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -428,6 +430,8 @@ "call_limit": "Market Call Limit", "close": "Close position", "coll_ratio": "Ratio", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Your collateral ratio is below %(mr)s which is not allowed.", @@ -445,6 +449,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "No valid feeds for %(asset_symbol)s", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s Margin", "update": "Update", "use_max": "Use Max" @@ -457,6 +462,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1477,6 +1483,8 @@ "password": "Password", "passwordLogin": "Login using the account model", "password_text": "Change your password.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "Remove", @@ -1495,7 +1503,11 @@ "show": "Show", "showAssetPercent": "Show asset percentages on the account page", "showSettles": "Show settle orders in depth chart", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Theme", "unit": "Unité de valeur préféré", "valid_node_url": "Node URL must begin with ws:// or wss://", @@ -1577,6 +1589,8 @@ "sync_no": "The current node is out of sync with the blockchain, try switching to another one", "sync_yes": "The current node is in sync with the blockchain", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Click here to make a transfer, or to deposit/withdraw those assets that support it.", "update_position": @@ -1613,6 +1627,7 @@ "coll_of": "avec collateral de", "coll_ratio": "Ratio de collateral initiale", "collateral": "Collateral", + "collateral_target": "Target Collateral", "committee_member_create": "A créé le délégué", "confirm": "Veuillez confirmer la transaction", "create_key": "A créé une cléf public", diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index 083d9400a4..87b3c078f7 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -423,6 +423,8 @@ "browser_text": "Il browser che stai usando non è stato pienamente testato per il supporto del portafoglio BitShares. Raccomandiamo caldamente di fare il backup del tuo portafoglio e importarlo usando il browser Chrome finché non avremo avuto il tempo di testare appieno il tuo browser. Usalo a tuo rischio.", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Connesso", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -438,6 +440,8 @@ "call_limit": "Market Call Limit", "close": "Chiudi posizione", "coll_ratio": "Collateral ratio", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Il tuo collateral ratio è inferiore a %(mr)s, che non è consentito.", @@ -455,6 +459,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "Nessun feed valido per %(asset_symbol)s", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s con margine", "update": "Aggiorna", "use_max": "Use Max" @@ -467,6 +472,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1497,6 +1503,8 @@ "password": "Password", "passwordLogin": "Fai il login usando il modalità account", "password_text": "Cambia la tua password.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "Rimuovi", @@ -1516,7 +1524,11 @@ "show": "mostra", "showAssetPercent": "Mostra percentuali asset nella pagina Account", "showSettles": "Mostra settlement nel depth chart", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Tema", "unit": "Unità preferite per l'account", "valid_node_url": @@ -1603,6 +1615,8 @@ "sync_no": "Il nodo corrente non è sincronizzato con la blockchain, prova a passare a un altro", "sync_yes": "Il nodo corrente è sincronizzato con la blockchain", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Clicca qui per effettuare un trasferimento, o per depositare/prelevare quegli asset che lo permettono.", "update_position": @@ -1639,6 +1653,7 @@ "coll_of": "con una garanzia di", "coll_ratio": "Rapporto di garanzia iniziale", "collateral": "Garanzia", + "collateral_target": "Target Collateral", "committee_member_create": "Ha creato il membro del comitato", "confirm": "Per favore conferma la transazione", "create_key": "Creata una chiave pubblica", diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index 24c62b0899..4a46945cdc 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -414,6 +414,8 @@ "browser_text": "使用しているブラウザはBitSharesウォレットをサポートするための完全なテストが行われていません。ウォレットをバックアップし、あなたが選択したブラウザの完全なテストが行われるまで、Chromeブラウザを使用することを強く推奨します。自身の責任で使用してください。", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "接続しました", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -429,6 +431,8 @@ "call_limit": "マーケットコールリミット", "close": "ポジションを閉じる", "coll_ratio": "担保比率", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "あなたの担保比率は%(mr)s未満であり、許可されません。", "below_info": @@ -445,6 +449,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "%(asset_symbol)sの有効なフィードがありません", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)sマージン", "update": "更新", "use_max": "Use Max" @@ -457,6 +462,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1474,6 +1480,8 @@ "password": "パスワード", "passwordLogin": "ログインモード", "password_text": "パスワードを変更する。", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "削除", @@ -1492,7 +1500,11 @@ "show": "表示", "showAssetPercent": "アカウントページにアセットパーセンテージを表示", "showSettles": "決済注文をデプスチャートで表示する", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "テーマ", "unit": "アカウントの単位選択", "valid_node_url": @@ -1578,6 +1590,8 @@ "sync_no": "現在のノードはブロックチェーンと同期していません。別のノードに切り替えてみてください。", "sync_yes": "現在のノードはブロックチェーンと同期しています。", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "転送または、サポートするアセットを入出金するにはここをクリックしてください。", "update_position": @@ -1613,6 +1627,7 @@ "coll_of": "担保: ", "coll_ratio": "初期担保比率", "collateral": "担保", + "collateral_target": "Target Collateral", "committee_member_create": "委員を作成する", "confirm": "取引を確認してください", "create_key": "公開キーを作成しました", diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index df6d1fa271..811dcc0f19 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -413,6 +413,8 @@ "browser_text": "The Browser you are using has not been fully tested to support the BitShares Wallet. We highly recommend that you backup your local wallet and import it using the Chrome Browser until we have had more time to fully test your browser of choice. Use at your own risk.", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "연결됨", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -428,6 +430,8 @@ "call_limit": "종목내 콜 한도", "close": "Close Position", "coll_ratio": "담보 비율", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Your collateral ratio is below %(mr)s which is not allowed.", @@ -445,6 +449,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "%(asset_symbol)s 에 대한 유효한 가격정보가 없음", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "Collateral position for %(asset_symbol)s", "update": "Update", "use_max": "Use Max" @@ -457,6 +462,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1472,6 +1478,8 @@ "password": "Password", "passwordLogin": "Login using the account model", "password_text": "Change your password.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "Remove", @@ -1490,7 +1498,11 @@ "show": "Show", "showAssetPercent": "Show asset percentages on the account page", "showSettles": "Show settle orders in depth chart", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Theme", "unit": "선호 화폐단위", "valid_node_url": "Node URL must begin with ws:// or wss://", @@ -1572,6 +1584,8 @@ "sync_no": "The current node is out of sync with the blockchain, try switching to another one", "sync_yes": "The current node is in sync with the blockchain", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Click here to make a transfer, or to deposit/withdraw those assets that support it.", "update_position": @@ -1607,6 +1621,7 @@ "coll_of": "with collateral of", "coll_ratio": "초기 담보 비율", "collateral": "담보", + "collateral_target": "Target Collateral", "committee_member_create": "위원 생성", "confirm": "거래 확인", "create_key": "공개키 생성", diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index c46e0686dc..72486c8f85 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -427,6 +427,8 @@ "browser_text": "Браузер, который Вы используете, не тестировался на поддержку кошелька %(wallet_name)s. Мы настоятельно рекомендуем Вам сделать резервную копию вашего локального кошелька и импортировать его, используя браузер Chrome, пока мы не найдем время, чтобы провести полное тестирование выбранного Вами браузера. Мы не несем ответственности за использование Вами данного браузера.", "check_latency": "Выполняется проверка задержки...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Соединение установлено", "connecting": "Подключение к серверу API: %(server)s", "database": @@ -443,6 +445,8 @@ "call_limit": "Предел", "close": "Закрыть позицию", "coll_ratio": "Коэффициент перекрытия", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Ваш уровень гарантийного обеспечения ниже %(mr)s, что не допускается.", @@ -460,6 +464,7 @@ "Прежде чем максимизировать долг, вы должны задать коэффициент залогового обеспечения", "no_valid": "Для %(asset_symbol)s нет действующих котировок", "pay_max_debt": "Выплатить максимальный долг", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s маржа", "update": "Обновить", "use_max": "Использовать максимум" @@ -472,6 +477,7 @@ "connection": { "automatic_reconnect": " Повторная попытка соединения будет совершена автоматически через %(reconnect_in_seconds)s секунд.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Переподключиться", "out_of_sync": "Ваше соединение потеряно %(out_of_sync_seconds)s секунд.", @@ -1503,6 +1509,8 @@ "password": "Пароль", "passwordLogin": "Режим входа", "password_text": "Поменяйте пароль.", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Проверить Узлы", "pinging": "Отслеживается...", "remove": "Удалить", @@ -1524,7 +1532,11 @@ "showAssetPercent": "Показать процентное соотношение активов на странице аккаунтов", "showSettles": "Показать ордера на погашение ордера на графике глубины", + "skipped": "Skipped", "switch": "Сменить узел", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Тема", "unit": "Предпочтительные единицы счета", "valid_node_url": "URL-адрес узла должен начинаться с ws:// или wss://", @@ -1612,6 +1624,8 @@ "sync_no": "Данный узел не синхронизирован с блокчейном, попробуйте переключиться на другой", "sync_yes": "Данный узел синхронизирован с блокчейном", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Нажмите здесь, чтобы совершить перевод или разместить депозит/вывести те активы, которые это позволяют.", "update_position": @@ -1647,6 +1661,7 @@ "coll_of": "с обеспечением", "coll_ratio": "Начальный коэффициент обеспечения", "collateral": "Обеспечение", + "collateral_target": "Target Collateral", "committee_member_create": "Создал члена комитета", "confirm": "Пожалуйста, подтвердите транзакцию", "create_key": "Создан публичный ключ", diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index 2c1a92f173..d9cc78a1a7 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -419,6 +419,8 @@ "browser_text": "Kullandığınız tarayıcı üzerinde testlerimiz devam etmektedir, bu yüzden BitShares Cüzdanını desteklemeyebilir. Cüzdanınızı yedekleyip Chrome Tarayıcısını kullanarak içeri aktarmanızı önemle tavsiye ederiz. Mesuliyet size aittir.", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "Bağlandı", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -434,6 +436,8 @@ "call_limit": "Piyasa Çağrı Limiti", "close": "Pozisyonu Kapat", "coll_ratio": "Teminat oranı", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "Teminat oranı çok düşük, bu pozisyon anında marjin-çağrılır", @@ -451,6 +455,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "%(asset_symbol)s için geçerli yayın mevcut değil", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s Marjin", "update": "Güncelle", "use_max": "Use Max" @@ -463,6 +468,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1489,6 +1495,8 @@ "password": "Şifre", "passwordLogin": "Login mode", "password_text": "Şifre değiştirme", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "Remove", @@ -1507,7 +1515,11 @@ "show": "Show", "showAssetPercent": "Bakiyeleri yüzde olarak da göster", "showSettles": "Derinlik tablosunda settle order'ları göster", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "Tema", "unit": "Tercih edilen hesap birimi", "valid_node_url": "Node URL must begin with ws:// or wss://", @@ -1589,6 +1601,8 @@ "sync_no": "The current node is out of sync with the blockchain, try switching to another one", "sync_yes": "The current node is in sync with the blockchain", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "Dijital ürün transferi ya da (eğer destekleniyorsa) yatırma-çekme işlemi yapmak için buraya tıklayın.", "update_position": @@ -1624,6 +1638,7 @@ "coll_of": "teminatıyla", "coll_ratio": "Başlangıç teminat oranı", "collateral": "Teminat", + "collateral_target": "Target Collateral", "committee_member_create": "Kurul üyesi oluşturuldu.", "confirm": "Lütfen işlemi teyit et", "create_key": "Açık anahtar oluşturuldu", diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index 35d6036ad8..f4af00c913 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -400,6 +400,8 @@ "browser_text": "你使用的浏览器未经过 BitShares 钱包软件的充分测试。强烈建议你备份钱包,并将其导入谷歌 Chrome 浏览器。今后经过我们充分测试后,你或许可以继续使用现在的浏览器。请了解相关风险。", "check_latency": "Running latency checks...", + "check_latency_feedback": + "Running latency checks (%(pinged)s/%(totalToPing)s nodes) ...", "connected": "已连接", "connecting": "Connecting to API server: %(server)s", "database": "Connection established, initializing local databases", @@ -415,6 +417,8 @@ "call_limit": "强制平仓价*", "close": "平仓", "coll_ratio": "抵押率", + "coll_ratio_target": "Target Ratio", + "enable_target_collateral_ratio": "Use Target Collateral Ratio", "errors": { "below": "抵押率低于要求的 %(mr)s,不允许操作", "below_info": @@ -431,6 +435,7 @@ "You must set a collateral ratio before being able to maximize debt", "no_valid": "无 %(asset_symbol)s 的有效喂价", "pay_max_debt": "Pay Max Debt", + "target_collateral_ratio": "Target Collateral Ratio", "title": "%(asset_symbol)s 抵押债仓", "update": "调整", "use_max": "Use Max" @@ -443,6 +448,7 @@ "connection": { "automatic_reconnect": " After %(reconnect_in_seconds)s seconds a reconnection attempt will be made automatically.", + "manual_ping": "Go to ping nodes", "manual_reconnect": "Reconnect now", "out_of_sync": "Your connection has been out of sync for %(out_of_sync_seconds)s seconds.", @@ -1433,6 +1439,8 @@ "password": "密码", "passwordLogin": "登录方式", "password_text": "修改钱包密码。", + "personal_active": + "Your only personal node is active, to remove or modify it you must first connect to a different node", "ping": "Ping Nodes", "pinging": "Pinging ...", "remove": "删除", @@ -1451,7 +1459,11 @@ "show": "显示", "showAssetPercent": "在账户页上显示资产/供应量占比", "showSettles": "在深度图中显示清算订单", + "skipped": "Skipped", "switch": "Switch Node", + "testnet_nodes": "Testnet", + "testnet_nodes_disclaimer": + "Availability of the testnet is not guaranteed. Establish a connection by connected manually to one of the nodes below:", "themes": "主题", "unit": "显示记账单位", "valid_node_url": "节点地址必须以 ws:// 或 wss:// 开头", @@ -1522,6 +1534,8 @@ "如果你是账户的所有人,请选中此项,以便正确对交易进行签名。仅当你当前使用的账户拥有此账户的账户权限,而没有资金权限时,需要开启此项。", "sync_no": "当前节点并未与区块链同步,请换一个节点。", "sync_yes": "当前节点已与区块链同步", + "target_collateral_ratio": + "Setting a target collateral ratio can help with not selling all of the posision at once.

    Sell as little by setting target below MCR (ex. 1.5)

    Sell as little but decrease possible margin calls again by setting it higher than MCR (ex. 3)", "transfer_actions": "点击这里进行转账,或充值/提取支持充提功能的资产。", "update_position": "更新债仓。你可随时更新债务及抵押物数量。", "withdraw_address": @@ -1554,6 +1568,7 @@ "coll_of": "抵押物为", "coll_ratio": "初始抵押率", "collateral": "抵押物", + "collateral_target": "Target Collateral", "committee_member_create": "创建理事会成员", "confirm": "请确认交易", "create_key": "创建公钥", diff --git a/app/assets/stylesheets/components/_modal.scss b/app/assets/stylesheets/components/_modal.scss index e3383003f7..82a26334f4 100644 --- a/app/assets/stylesheets/components/_modal.scss +++ b/app/assets/stylesheets/components/_modal.scss @@ -141,4 +141,3 @@ label.ant-checkbox-wrapper { text-transform: none; } } - \ No newline at end of file diff --git a/app/assets/stylesheets/components/_settings.scss b/app/assets/stylesheets/components/_settings.scss index a39dd3b32f..e9a8346b1c 100644 --- a/app/assets/stylesheets/components/_settings.scss +++ b/app/assets/stylesheets/components/_settings.scss @@ -60,12 +60,18 @@ div.api-node { padding-top: 1rem; padding-left: 1rem; } - > div:nth-child(1) { + > div.api-node-left { width: 50%; - > p:nth-child(2) { + > p.api-node-url { overflow-wrap: break-word; font-size: 80%; } + > p.api-node-operator { + overflow-wrap: break-word; + font-size: 80%; + float: right; + color: gray; + } } > div:nth-child(2) { width: 25%; diff --git a/app/branding.js b/app/branding.js index 5e8941cfbb..5d71b33920 100644 --- a/app/branding.js +++ b/app/branding.js @@ -29,7 +29,7 @@ export function getFaucet() { return { url: "https://faucet.bitshares.eu/onboarding", // 2017-12-infrastructure worker proposal show: true, - editable: true + editable: false }; } diff --git a/app/components/Account/MarginPositions.jsx b/app/components/Account/MarginPositions.jsx index b4923ac24d..ea15254b9e 100644 --- a/app/components/Account/MarginPositions.jsx +++ b/app/components/Account/MarginPositions.jsx @@ -295,7 +295,9 @@ class MarginPosition extends React.Component { {/* / */} / */} - {!!c.order.target_collateral_ratio ? (c.order.target_collateral_ratio / 1000).toFixed(3) : "-"} + {!!c.order.target_collateral_ratio + ? (c.order.target_collateral_ratio / 1000).toFixed( + 3 + ) + : "-"} {c.getRatio().toFixed(3)} diff --git a/app/components/Blockchain/Transaction.jsx b/app/components/Blockchain/Transaction.jsx index ddccddf988..02a03c2526 100644 --- a/app/components/Blockchain/Transaction.jsx +++ b/app/components/Blockchain/Transaction.jsx @@ -439,7 +439,10 @@ class Transaction extends React.Component { ); - {!!op[1].extensions && !!op[1].extensions.target_collateral_ratio ? + if ( + !!op[1].extensions && + !!op[1].extensions.target_collateral_ratio + ) { rows.push( @@ -449,11 +452,13 @@ class Transaction extends React.Component { /> - {op[1].extensions.target_collateral_ratio / 1000} + {op[1].extensions.target_collateral_ratio / + 1000} - ) - : null} + ); + } + break; case "key_create": diff --git a/app/components/BrowserNotifications/BrowserNotificationsContainer.jsx b/app/components/BrowserNotifications/BrowserNotificationsContainer.jsx index 29247acbd0..b8c86726df 100644 --- a/app/components/BrowserNotifications/BrowserNotificationsContainer.jsx +++ b/app/components/BrowserNotifications/BrowserNotificationsContainer.jsx @@ -4,6 +4,10 @@ import SettingsStore from "stores/SettingsStore"; import AltContainer from "alt-container"; import BrowserNotifications from "./BrowserNotifications"; +const Wrapper = props => { + return !!props.account ? : null; +}; + class BrowserNotificationsContainer extends React.Component { render() { return ( @@ -18,7 +22,7 @@ class BrowserNotificationsContainer extends React.Component { } }} > - + ); } diff --git a/app/components/Layout/Footer.jsx b/app/components/Layout/Footer.jsx index 462e35d4e1..1ca8486c9f 100644 --- a/app/components/Layout/Footer.jsx +++ b/app/components/Layout/Footer.jsx @@ -16,7 +16,7 @@ import PropTypes from "prop-types"; import {routerTransitioner} from "../../routerTransition"; import LoadingIndicator from "../LoadingIndicator"; import counterpart from "counterpart"; -import ConfirmModal from "../Modal/ConfirmModal"; +import ChoiceModal from "../Modal/ChoiceModal"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; import {ChainStore} from "bitsharesjs"; import ifvisible from "ifvisible"; @@ -148,12 +148,15 @@ class Footer extends React.Component { getNode(node) { const {props} = this; + let title = node.operator + " " + !!node.location ? node.location : ""; + if (!!node.country) { + title = node.country + (!!title ? " - " + title : ""); + } + return { - name: node.location || "Unknown location", + name: title, url: node.url, - up: node.url in props.apiLatencies, - ping: props.apiLatencies[node.url], - hidden: !!node.hidden + ping: props.apiLatencies[node.url] }; } @@ -235,7 +238,7 @@ class Footer extends React.Component { // not receive anymore blocks, meaning no rerender. Thus we need to trigger any and all // handling out of sync state within this one call - let forceReconnectAfterSeconds = 60; + let forceReconnectAfterSeconds = this._getForceReconnectAfterSeconds(); let askToReconnectAfterSeconds = 5; // Trigger automatic reconnect after X seconds @@ -256,51 +259,12 @@ class Footer extends React.Component { ); setTimeout(() => { // Only ask the user once, and only continue if still out of sync - let out_of_sync_seconds = this.getBlockTimeDelta(); if ( this.getBlockTimeDelta() > 3 && this.confirmOutOfSync.shownOnce == false ) { this.confirmOutOfSync.shownOnce = true; - this.confirmOutOfSync.modal.show( -
    - -
    -
    - -
    -
    - - {routerTransitioner.isAutoSelection() && ( - - )} -
    -
    -
    -
    , - , - () => { - if (!this.props.synced) { - this._triggerReconnect(false); - } - } - ); + this.confirmOutOfSync.modal.show(); } }, askToReconnectAfterSeconds * 1000); } @@ -310,6 +274,10 @@ class Footer extends React.Component { } } + _getForceReconnectAfterSeconds() { + return 60; + } + _triggerReconnect(honorManualSelection = true) { if (honorManualSelection && !routerTransitioner.isAutoSelection()) { return; @@ -364,20 +332,62 @@ class Footer extends React.Component { {!!routerTransitioner && routerTransitioner.isTransitionInProgress() && ( )} - { this.confirmOutOfSync.modal = thiz; }} - /> + choices={[ + { + translationKey: "connection.manual_reconnect", + callback: () => { + if (!this.props.synced) { + this._triggerReconnect(false); + } + } + }, + { + translationKey: "connection.manual_ping", + callback: () => { + if (!this.props.synced) { + this.onAccess(); + } + } + } + ]} + > +
    + +
    +
    + +
    +
    + + {routerTransitioner.isAutoSelection() && ( + + )} +
    +
    diff --git a/app/components/Modal/BorrowModal.jsx b/app/components/Modal/BorrowModal.jsx index 1a21897784..4b68a2c8f3 100755 --- a/app/components/Modal/BorrowModal.jsx +++ b/app/components/Modal/BorrowModal.jsx @@ -60,7 +60,9 @@ class BorrowModalContent extends React.Component { props.backing_asset ); - let target_collateral_ratio = !isNaN(currentPosition.target_collateral_ratio) + let target_collateral_ratio = !isNaN( + currentPosition.target_collateral_ratio + ) ? currentPosition.target_collateral_ratio / 1000 : 0; @@ -432,20 +434,26 @@ class BorrowModalContent extends React.Component { ); let currentPosition = this._getCurrentPosition(this.props); - let isTCR = typeof(this.state.target_collateral_ratio) !== "undefined" - && this.state.target_collateral_ratio > 0 - && this.state.useTargetCollateral - ? true - : false; - + let isTCR = + typeof this.state.target_collateral_ratio !== "undefined" && + this.state.target_collateral_ratio > 0 && + this.state.useTargetCollateral + ? true + : false; + let extensionsProp = false; - if(isTCR) { - extensionsProp = { target_collateral_ratio: parseInt(this.state.target_collateral_ratio * 1000, 10) }; + if (isTCR) { + extensionsProp = { + target_collateral_ratio: parseInt( + this.state.target_collateral_ratio * 1000, + 10 + ) + }; } var tr = WalletApi.new_transaction(); - if(extensionsProp) { + if (extensionsProp) { tr.add_type_operation("call_order_update", { fee: { amount: 0, @@ -492,7 +500,7 @@ class BorrowModalContent extends React.Component { 10 ), asset_id: this.props.quote_asset.get("id") - }, + } }); } WalletDb.process_transaction(tr, null, true).catch(err => { @@ -984,28 +992,37 @@ class BorrowModalContent extends React.Component { className="tooltip" data-html={true} data-tip={counterpart.translate( - "tooltip.target_collateral_ratio" - )}> + "tooltip.target_collateral_ratio" + )} + > - {useTargetCollateral ? + {useTargetCollateral ? ( -
    - + + >
    -
    - : + ) : (
    - +
    - } + )}
    diff --git a/app/components/Modal/ChoiceModal.js b/app/components/Modal/ChoiceModal.js new file mode 100644 index 0000000000..2e8c9dd2db --- /dev/null +++ b/app/components/Modal/ChoiceModal.js @@ -0,0 +1,84 @@ +import React from "react"; +import PropTypes from "prop-types"; +import ZfApi from "react-foundation-apps/src/utils/foundation-api"; +import BaseModal from "./BaseModal"; +import Trigger from "react-foundation-apps/src/trigger"; +import Translate from "react-translate-component"; +import counterpart from "counterpart"; + +class ChoiceModal extends React.Component { + static propTypes = { + modalId: PropTypes.string.isRequired, + choices: PropTypes.array.isRequired, + content: PropTypes.object + }; + + static defaultProps = { + content: null + }; + + constructor() { + super(); + this.state = { + show: false + }; + } + + show() { + this.setState({show: true}); + ZfApi.publish(this.props.modalId, "open"); + } + + confirmClicked(callback, e) { + e.preventDefault(); + ZfApi.publish(this.props.modalId, "close"); + setTimeout(() => { + this.setState({show: false}); + }, 500); + callback(); + } + + render() { + return ( + + {this.state.show && ( +
    + {this.props.content} + {React.Children.map(this.props.children, (child, i) => { + let props = {}; + props["key"] = i + ""; + return React.cloneElement(child, props); + })} +
    +
    +
    +
    + {this.props.choices.map(child => { + return ( + + + + ); + })} + +
    + +
    +
    +
    +
    + )} +
    + ); + } +} + +export default ChoiceModal; diff --git a/app/components/Settings/AccessSettings.jsx b/app/components/Settings/AccessSettings.jsx index 611ece8ebe..3a701df53a 100644 --- a/app/components/Settings/AccessSettings.jsx +++ b/app/components/Settings/AccessSettings.jsx @@ -9,26 +9,112 @@ import cnames from "classnames"; import Icon from "../Icon/Icon"; import LoadingButton from "../Utility/LoadingButton"; -const autoSelectAPI = "wss://fake.automatic-selection.com"; -const testnetAPI = settingsAPIs.WS_NODE_LIST.find( - a => a.url.indexOf("node.testnet.bitshares.eu") !== -1 -); -const testnetAPI2 = settingsAPIs.WS_NODE_LIST.find( - a => a.url.indexOf("testnet.nodes.bitshares.ws") !== -1 -); +const autoSelectionUrl = "wss://fake.automatic-selection.com"; function isTestNet(url) { - if (!!testnetAPI || !!testnetAPI2) { - return url === testnetAPI.url || url === testnetAPI2.url; + return !__TESTNET__ && url.indexOf("testnet") !== -1; +} + +/** + * This class renders the auto-selection node + */ +class AutoSelectionNode extends React.Component { + constructor(props) { + super(props); + } + + /** + * On activation routerTransitioner selects the best by itself. On deactivation the currently connected, or + * last connected node is selected again. + * + * @param url + */ + activate(url) { + SettingsActions.changeSetting({ + setting: "apiServer", + value: url + }); + if ( + SettingsStore.getSetting("activeNode") != + SettingsStore.getSetting("apiServer") + ) { + setTimeout( + function() { + willTransitionTo(false); + }.bind(this), + 50 + ); + } + } + + render() { + const {isActive, connectedNode, totalNodes, popup} = this.props; + + if (popup) { + return ( +
    + + {}} + /> + + +

    + : +

    +
    + ); + } else { + return ( +
    +
    + + {}} + /> + + +
    +
    + ); + } } - return false; } /** * This class renders a a single node within the nodes list in the settings overview. * * This includes: - * - rendering the fake-auto-select node as a slider for activation * - rendering the currently active node * - render all other nodes with or without ping in the three sections: * available, hidden, personal @@ -38,6 +124,10 @@ class ApiNode extends React.Component { super(props); } + /** + * Nodes can only be activated, as switching only works by activating another + * @param url + */ activate(url) { SettingsActions.changeSetting({ setting: "apiServer", @@ -69,88 +159,98 @@ class ApiNode extends React.Component { SettingsActions.hideWS(url); } - render() { - const {props, state} = this; - const { - allowActivation, - allowRemoval, - automatic, - autoActive, - name, - url, - displayUrl, - ping, - up, - hidden, - activeNode, - popup - } = props; - - let color; - let latencyKey; - let friendlyPing; - - if (ping < 400) { + /** + * Construct ping dict containing toString, color and rating. + * @returns {*} + * @private + */ + _getPing() { + if (isTestNet(this.props.node.url)) { + return { + toString: null, + color: null, + rating: null + }; + } + if (!this.props.node.ping) { + return { + toString: null, + color: "high", + rating: "node_down" + }; + } + if (this.props.node.ping == Infinity) { + return { + toString: null, + color: "high", + rating: "node_down" + }; + } + if (this.props.node.ping == -1) { + return { + toString: null, + color: "high", + rating: "skipped" + }; + } + let color, rating; + let pingInMs = this.props.node.ping; + if (pingInMs < 400) { color = "low"; - latencyKey = "low_latency"; - } else if (ping >= 400 && ping < 800) { + rating = "low_latency"; + } else if (pingInMs >= 400 && pingInMs < 800) { color = "medium"; - latencyKey = "medium_latency"; + rating = "medium_latency"; } else { color = "high"; - latencyKey = "high_latency"; + rating = "high_latency"; } - friendlyPing = - ping >= 1000 ? +(ping / 1000).toFixed(2) + "s" : ping + "ms"; + return { + toString: + pingInMs >= 1000 + ? +(pingInMs / 1000).toFixed(2) + "s" + : pingInMs + "ms", + color: color, + rating: rating + }; + } - //console.log("Active: " + activeNode.url + " Current: " + currentNode); + render() { + const {node, isActive, popup} = this.props; - /* - * The testnet latency is not checked in the connection manager, - * so we force enable activation of it even though it shows as 'down' - * - */ - const isTestnet = isTestNet(url); + let ping = this._getPing(); - let totalNodes = settingsAPIs.WS_NODE_LIST.length - 3; + let url = node.url; - let isActive = activeNode.url == url; - let showControls = !isActive && !automatic; + let canBeHidden = !isActive; + let canBeRemoved = !node.default && !isActive; - if (popup) { - return url === autoSelectAPI ? ( -
    - - {}} - /> - + let hidden = !!node.hidden; -

    - : -

    -
    + let location = + !!node.location && + typeof node.location === "object" && + "translate" in node.location ? ( + ) : ( + node.location + ); + + let title = !!location ? location : ""; + if (!!node.country) { + title = node.country + (!!title ? " - " + title : ""); + } + if (!!node.region) { + title = node.region + (!!title ? " - " + title : ""); + } + + if (popup) { + return (
    - {name} + {title}
    ); } else { - return url === autoSelectAPI ? ( -
    -
    - - {}} - /> - - - {/* - // FOR FUTURE PING NODES FEATURE -
    - -
    */} -
    -
    - ) : ( + return (
    -
    -

    {name}

    -

    - {displayUrl} +

    +

    {title}

    + {!!node.operator && ( +

    + {node.operator}    +

    + )} +

    + {url}

    - {isTestnet && !ping ? null : ( -
    - {!up ? ( - - - - ) : ( - - -

    {friendlyPing}

    -
    +
    + + {!!ping.rating && ( + )} -
    - )} + {!!ping.toString &&

    {ping.toString}

    } + +
    - {showControls && - hidden && ( - - - - )} - {showControls && - !hidden && ( - - - - )} - {showControls && - allowRemoval && ( - - - - )} + {canBeHidden && ( + + )} + {canBeRemoved && ( + + + + )}
    - {activeNode.url != url ? ( + {!isActive ? ( ) : ( { - isDefaultNode[node.url] = true; + /** + * Copies all keys in the default apiServer and adds the ping + * + * @param node + * @returns {{ping: *}} + */ + getNode(node) { + const {props} = this; + let nodeWrapper = { + ping: props.apiLatencies[node.url] + }; + Object.keys(node).forEach(key => { + nodeWrapper[key] = node[key]; }); - - this.isDefaultNode = isDefaultNode; + return nodeWrapper; } - getNodeIndexByURL(url) { - const {nodes} = this.props; - - let index = nodes.findIndex(node => node.url === url); - if (index === -1) { - return null; - } - return index; + _getConnectedNode() { + return this.getNode( + this.props.nodes.find(node => node.url == this.props.connectedNode) + ); } - getCurrentNodeIndex() { - const {props} = this; - let currentNode = this.getNodeIndexByURL.call(this, props.currentNode); - - return currentNode; + _connectedNodeIsPersonal() { + let cn = this.props.nodes.find( + node => node.url == this.props.connectedNode + ); + return cn && this._nodeIsPersonal(cn); } - getNode(node) { - const {props} = this; + _nodeIsPersonal(node) { + return !node.default && !node.hidden && !isTestNet(node.url); + } - return { - name: node.location || "Unknown location", - url: node.url, - up: node.url in props.apiLatencies, - ping: props.apiLatencies[node.url], - hidden: !!node.hidden - }; + _getMainNetNodes() { + return this.props.nodes.filter(a => { + return !isTestNet(a.url); + }); } - renderNode(node, activeNode, allowActivation) { + /** + * @param node either a string (and then au + * @param connectedNode + * @returns {XML} + */ + renderNode(node, connectedNode) { const {props} = this; - let automatic = node.url === autoSelectAPI; - - let displayUrl = automatic ? "..." : node.url; - - let name = - !!node.name && - typeof node.name === "object" && - "translate" in node.name ? ( - - ) : ( - node.name - ); - - let allowRemoval = - !automatic && !this.isDefaultNode[node.url] ? true : false; - return ( + ); + } + + renderAutoSelection(connectedNode) { + const {props} = this; + + return ( + ); @@ -404,13 +457,6 @@ class AccessSettings extends React.Component { }); } - /* _recalculateLatency(event, feedback) { - feedback("Pinging all nodes"); - routerTransitioner.doLatencyUpdate().then(()=>{ - feedback(); - }); - }*/ - _recalculateLatency(event, feedback) { feedback("settings.pinging"); routerTransitioner.doLatencyUpdate(true, null).finally(() => { @@ -420,108 +466,89 @@ class AccessSettings extends React.Component { render() { const {props} = this; + + // placeholder to avoid this mismatch let getNode = this.getNode.bind(this); let renderNode = this.renderNode.bind(this); - let currentNodeIndex = this.getCurrentNodeIndex.call(this); - let hc = "nodes-header clickable"; - let showAvailableNodes = this.state.activeTab !== "hidden-nodes"; - let availableClass = cnames(hc, { - inactive: this.state.activeTab !== "available-nodes" - }); - let hiddenClass = cnames(hc, { - inactive: this.state.activeTab !== "hidden-nodes" - }); - let myClass = cnames(hc, { - inactive: this.state.activeTab !== "my-nodes" - }); - let activeNode = getNode( - props.nodes[currentNodeIndex] || props.nodes[0] - ); + // currently selected and active node + let connectedNode = this._getConnectedNode(); - if (activeNode.url == autoSelectAPI) { - let nodeUrl = props.activeNode; - currentNodeIndex = this.getNodeIndexByURL.call(this, nodeUrl); - activeNode = getNode(props.nodes[currentNodeIndex]); - } - - let nodes = props.nodes + let allNodesExceptConnected = props.nodes .map(node => { return getNode(node); }) .filter(node => { - return node.url !== activeNode.url; + return ( + node.url !== connectedNode.url && + node.url !== autoSelectionUrl + ); + }) + .sort(function(a, b) { + let isTestnet = isTestNet(a.url); + if (!!a.ping && !!b.ping) { + return a.ping - b.ping; + } else if (!a.ping && !b.ping) { + if (isTestnet) return -1; + return 1; + } else if (!!a.ping && !b.ping) { + return -1; + } else if (!!b.ping && !a.ping) { + return 1; + } + return 0; }); - nodes = nodes.sort(function(a, b) { - let isTestnet = isTestNet(a.url); - if (a.url == autoSelectAPI) { - return -1; - } else if (a.up && b.up) { - return a.ping - b.ping; - } else if (!a.up && !b.up) { - if (isTestnet) return -1; - return 1; - } else if (a.up && !b.up) { - return -1; - } else if (b.up && !a.up) { - return 1; - } - - return 0; - }); - - if (this.state.activeTab === "my-nodes") { - nodes = nodes.filter(node => { - return !this.isDefaultNode[node.url]; + let nodesToShow = null; + let onlyPersonalNodeActive = false; + if (this.state.activeTab === "my_nodes") { + nodesToShow = allNodesExceptConnected.filter(node => { + return this._nodeIsPersonal(node); + }); + onlyPersonalNodeActive = + this._connectedNodeIsPersonal() && nodesToShow.length === 0; + } else if (this.state.activeTab === "available_nodes") { + nodesToShow = allNodesExceptConnected.filter(node => { + return node.default && !node.hidden && !isTestNet(node.url); + }); + } else if (this.state.activeTab === "testnet_nodes") { + nodesToShow = allNodesExceptConnected.filter(node => { + return isTestNet(node.url); }); } else { - nodes = nodes.filter(node => { - return ( - node.hidden !== showAvailableNodes && - this.isDefaultNode[node.url] - ); + nodesToShow = allNodesExceptConnected.filter(node => { + return node.hidden && !isTestNet(node.url); }); } - let autoNode = getNode(props.nodes[0]); let popupCount = 0; - let uniqueNodes = nodes.reduce((a, node) => { - let exists = - a.findIndex(n => { - return n.url === node.url; - }) !== -1; - - if (!exists) a.push(node); - return a; - }, []); return this.props.popup ? (
    - {renderNode(autoNode, activeNode, false)} + {this.renderAutoSelection(connectedNode)}
    - {uniqueNodes.map(node => { - if (node.url !== autoSelectAPI) { - popupCount++; - if (popupCount <= 5) { - return renderNode(node, activeNode, true); - } + {nodesToShow.map(node => { + popupCount++; + if (popupCount <= 5) { + return renderNode(node, connectedNode); } })}
    ) : (
    - {renderNode(autoNode, activeNode, false)} + {this.renderAutoSelection(connectedNode)}
    - {renderNode(activeNode, activeNode, false)} + {renderNode(connectedNode, connectedNode)}
    -
    - -
    -
    - -
    -
    - -
    + {[ + "available_nodes", + "my_nodes", + "hidden_nodes", + "testnet_nodes" + ].map(key => { + return ( +
    + +
    + ); + })}
    - {this.state.activeTab !== "my-nodes" ? null : ( + {this.state.activeTab === "my_nodes" && (
    @@ -584,10 +614,25 @@ class AccessSettings extends React.Component {
    )} - {uniqueNodes.map(node => { - if (node.url !== autoSelectAPI) - return renderNode(node, activeNode, true); + {this.state.activeTab === "testnet_nodes" && ( + + )} + {nodesToShow.map(node => { + return renderNode(node, connectedNode); })} + {onlyPersonalNodeActive ? ( +
    +

    + +

    +
    + ) : null}
    ); @@ -600,8 +645,10 @@ AccessSettings = connect(AccessSettings, { }, getProps() { return { - currentNode: SettingsStore.getState().settings.get("apiServer"), - activeNode: SettingsStore.getState().settings.get("activeNode"), + // apiServer and activeNode are ambiguous definition when dealing with isActive, autoSelectionActive etc.. + // using distinct names + selectedNode: SettingsStore.getState().settings.get("apiServer"), + connectedNode: SettingsStore.getState().settings.get("activeNode"), apiLatencies: SettingsStore.getState().apiLatencies }; } diff --git a/app/routerTransition.js b/app/routerTransition.js index beede5612a..041ed9a3f1 100644 --- a/app/routerTransition.js +++ b/app/routerTransition.js @@ -9,6 +9,7 @@ import WalletManagerStore from "stores/WalletManagerStore"; import WalletDb from "stores/WalletDb"; import SettingsStore from "stores/SettingsStore"; import AccountStore from "stores/AccountStore"; +import {settingsAPIs} from "api/apiConfig"; import ls from "common/localStorage"; @@ -87,9 +88,7 @@ class RouterTransitioner { // set auto selection flag this._autoSelection = - SettingsStore.getSetting("apiServer").indexOf( - "fake.automatic-selection" - ) !== -1; + this._getLastNode().indexOf("fake.automatic-selection") !== -1; this._initConnectionManager(urls); @@ -115,15 +114,64 @@ class RouterTransitioner { }); } + isAutoSelection() { + return this._autoSelection; + } + + isTransitionInProgress() { + return !!this._willTransitionToInProgress; + } + + getTransitionTarget() { + if (this.isTransitionInProgress()) + return this._willTransitionToInProgress; + return null; + } + + updateTransitionTarget(update) { + this._willTransitionToInProgress = update; + if (this._statusCallback != null) { + this._statusCallback(update); + } + } + /** - * Called when connection to a node has been established + * Updates the latency of all target nodes * - * @param resolveOrReject - * @private + * @param nodeUrls list of string nodes to update + * @returns {Promise} */ - _transitionDone(resolveOrReject) { - resolveOrReject(); - this._willTransitionToInProgress = false; + doQuickLatencyUpdate(nodeUrls) { + return new Promise((resolve, reject) => { + let url = this._connectionManager.url; + let urls = this._connectionManager.urls; + + if (typeof nodeUrls === "string") { + nodeUrls = [nodeUrls]; + } + this._connectionManager.url = nodeUrls[0]; + this._connectionManager.urls = nodeUrls.slice(1, nodeUrls.length); + + this._connectionManager + .checkConnections() + .then(res => { + console.log("Following nodes have been pinged:", res); + // update the latencies object + const apiLatencies = SettingsStore.getState().apiLatencies; + for (var nodeUrl in res) { + apiLatencies[nodeUrl] = res[nodeUrl]; + } + SettingsActions.updateLatencies(apiLatencies); + }) + .catch(err => { + console.log("doLatencyUpdate error", err); + }) + .finally(() => { + this._connectionManager.url = url; + this._connectionManager.urls = urls; + resolve(); + }); + }); } /** @@ -195,7 +243,7 @@ class RouterTransitioner { if (range == null) { range = this._connectionManager.urls.length; } else { - SettingsActions.updateLatencies({}); + this._clearLatencies(); } function local_ping(thiz, range = null) { @@ -239,9 +287,10 @@ class RouterTransitioner { "ms, stopping latency update" ); current = urls.length; + break; } } - SettingsActions.updateLatencies(apiLatencies); + thiz._updateLatencies(res); }) .catch(err => { console.log("doLatencyUpdate error", err); @@ -261,12 +310,38 @@ class RouterTransitioner { thiz._connectionManager.url = url; // resort the api nodes with the new pings thiz._connectionManager.urls = thiz._getNodesToConnectTo(); - resolve(); + thiz._transitionDone(resolve); } local_ping(this, range); }); } + _clearLatencies() { + SettingsActions.updateLatencies({}); + } + + _updateLatencies(mapOfPings, force = true) { + const apiLatencies = SettingsStore.getState().apiLatencies; + for (let node in mapOfPings) { + if (!force && node in apiLatencies) { + continue; + } + apiLatencies[node] = mapOfPings[node]; + } + SettingsActions.updateLatencies(apiLatencies); + } + + /** + * Called when connection to a node has been established + * + * @param resolveOrReject + * @private + */ + _transitionDone(resolveOrReject) { + resolveOrReject(); + this._willTransitionToInProgress = false; + } + _initConnectionManager(urls = null) { if (urls == null) { urls = this._getNodesToConnectTo(true); @@ -302,27 +377,6 @@ class RouterTransitioner { // Possibly do something about auto reconnect attempts here } - isAutoSelection() { - return this._autoSelection; - } - - isTransitionInProgress() { - return !!this._willTransitionToInProgress; - } - - updateTransitionTarget(update) { - this._willTransitionToInProgress = update; - if (this._statusCallback != null) { - this._statusCallback(update); - } - } - - getTransitionTarget() { - if (this.isTransitionInProgress()) - return this._willTransitionToInProgress; - return null; - } - /** * * @param apiNodeUrl the url of the target node, e.g. wss://eu.nodes.bitshares.ws @@ -445,6 +499,32 @@ class RouterTransitioner { return this.getNodes(latenciesMap, !all).map(a => a.url); // drop location, only urls in list } + /** + * Get the node that the user has chosen to connect to / has been able to connect to through fallback + * + * @returns {*} + * @private + */ + _getLastNode() { + return SettingsStore.getSetting("apiServer"); + } + + /** + * Set the node that the user wants to connect to / has fallen back to due to connection error + * + * @param url + * @private + */ + _setLastNode(url) { + // only update settings if changed + if (SettingsStore.getSetting("apiServer") !== url) { + SettingsActions.changeSetting({ + setting: "apiServer", + value: url + }); + } + } + /** * Returns the the one last url node connected to, with fallback the lowest latency one if * > there was no last connection @@ -456,25 +536,24 @@ class RouterTransitioner { * @private */ _getFirstToTry(urls) { - let connectionString = SettingsStore.getSetting("apiServer"); + let tryThisNode = this._getLastNode(); // fallback to the best of the pre-defined URLs ... // ... if there is no preset connectionString fallback to lowest latency - if (!connectionString) connectionString = urls[0]; + if (!tryThisNode) tryThisNode = urls[0]; // ... if auto selection is on (is also ensured in initConnection, but we don't want to ping // a unreachable url) if (this.isAutoSelection()) { - connectionString = urls[0]; - console.log("auto selecting to " + connectionString); + tryThisNode = urls[0]; + console.log("auto selecting to " + tryThisNode); } // ... if insecure websocket url is used when using secure protocol // (the list urls only contains matching ones) - if (!this._apiUrlSecuritySuitable(connectionString)) - connectionString = urls[0]; + if (!this._apiUrlSecuritySuitable(tryThisNode)) tryThisNode = urls[0]; - return connectionString; + return tryThisNode; } /** @@ -508,10 +587,7 @@ class RouterTransitioner { .connectWithFallback(true) .then(() => { if (!this.isAutoSelection()) { - SettingsActions.changeSetting({ - setting: "apiServer", - value: this._connectionManager.url - }); + this._setLastNode(this._connectionManager.url); } this._onConnect(resolve, reject); }) @@ -533,10 +609,7 @@ class RouterTransitioner { // in case switches manually, reset the settings so we dont connect to // a faulty node twice. If connection is established, onConnect sets the settings again if (!this.isAutoSelection()) { - SettingsActions.changeSetting({ - setting: "apiServer", - value: "" - }); + this._setLastNode(""); } this._attemptReconnect(resolve, reject); } @@ -606,23 +679,14 @@ class RouterTransitioner { `${Apis.instance().url} does not support the orders api` ); let currentUrl = Apis.instance().url; - SettingsActions.changeSetting({ - setting: "activeNode", - value: currentUrl - }); - if (!this.isAutoSelection()) - SettingsActions.changeSetting({ - setting: "apiServer", - value: currentUrl - }); - const apiLatencies = SettingsStore.getState().apiLatencies; - if (!(currentUrl in apiLatencies)) { - // the ping calculated here does not reflect the same ping as in checkConnection from ConnectionManager, - // thus updating would be "unfair" and also is confusing in UI - apiLatencies[currentUrl] = - new Date().getTime() - this._connectionStart; - SettingsActions.updateLatencies(apiLatencies); - } + if (!this.isAutoSelection()) this._setLastNode(currentUrl); + + // the ping calculated here does not reflect the same ping as in checkConnection from ConnectionManager, + // thus always updating would be "unfair" and also is confusing in UI + let mapOfPings = {}; + mapOfPings[currentUrl] = + new Date().getTime() - this._connectionStart; + this._updateLatencies(mapOfPings, false); } const currentChain = Apis.instance().chain_id; const chainChanged = this._oldChain !== currentChain; diff --git a/app/stores/SettingsStore.js b/app/stores/SettingsStore.js index 1df3605232..64088dbfcb 100644 --- a/app/stores/SettingsStore.js +++ b/app/stores/SettingsStore.js @@ -2,7 +2,6 @@ import alt from "alt-instance"; import SettingsActions from "actions/SettingsActions"; import IntlActions from "actions/IntlActions"; import Immutable, {fromJS} from "immutable"; -import {merge} from "lodash-es"; import ls from "common/localStorage"; import {Apis} from "bitsharesjs-ws"; import {settingsAPIs} from "api/apiConfig"; @@ -19,6 +18,9 @@ const CORE_ASSET = "BTS"; // Setting this to BTS to prevent loading issues when const STORAGE_KEY = "__graphene__"; let ss = new ls(STORAGE_KEY); +/** + * SettingsStore takes care of maintaining user set settings values and notifies all listeners + */ class SettingsStore { constructor() { this.exportPublicMethods({ @@ -28,6 +30,7 @@ class SettingsStore { setLastBudgetObject: this.setLastBudgetObject.bind(this) }); + // bind actions to store this.bindListeners({ onSetExchangeLastExpiration: SettingsActions.setExchangeLastExpiration, @@ -53,7 +56,42 @@ class SettingsStore { }); this.initDone = false; - this.defaultSettings = Immutable.Map({ + + this.settings = Immutable.Map(this._getSetting()); + + // deprecated to support existing code + this.defaultSettings = Immutable.Map(this._getDefaultSetting()); + + // this should be called choices, defaults is confusing + this.defaults = this._getChoices(); + + this.viewSettings = Immutable.Map(ss.get("viewSettings_v1")); + this.marketDirections = Immutable.Map(ss.get("marketDirections")); + + this.hiddenAssets = Immutable.List(ss.get("hiddenAssets", [])); + this.hiddenMarkets = Immutable.List(ss.get("hiddenMarkets", [])); + + this.apiLatencies = ss.get("apiLatencies", {}); + + this.mainnet_faucet = ss.get( + "mainnet_faucet", + settingsAPIs.DEFAULT_FAUCET + ); + this.testnet_faucet = ss.get( + "testnet_faucet", + settingsAPIs.TESTNET_FAUCET + ); + + this.exchange = fromJS(ss.get("exchange", {})); + } + + /** + * Returns the default selected values that the user can reset to + * @returns dictionary + * @private + */ + _getDefaultSetting() { + return { locale: "en", apiServer: settingsAPIs.DEFAULT_WS_NODE, faucet_address: settingsAPIs.DEFAULT_FAUCET, @@ -69,13 +107,16 @@ class SettingsStore { transferToMe: true } } - }); - - // If you want a default value to be translated, add the translation to settings in locale-xx.js - // and use an object {translate: key} in the defaults array - let apiServer = settingsAPIs.WS_NODE_LIST; + }; + } - let defaults = { + /** + * All possible choices for the settings + * @returns dictionary + * @private + */ + _getDefaultChoices() { + return { locale: [ "en", "zh", @@ -88,7 +129,7 @@ class SettingsStore { "ru", "ja" ], - apiServer: apiServer, + apiServer: settingsAPIs.WS_NODE_LIST.slice(0), // clone all default servers as configured in apiConfig.js unit: getUnits(), showSettles: [{translate: "yes"}, {translate: "no"}], showAssetPercent: [{translate: "yes"}, {translate: "no"}], @@ -97,86 +138,261 @@ class SettingsStore { {translate: "cloud_login"}, {translate: "local_wallet"} ] - // confirmMarketOrder: [ - // {translate: "confirm_yes"}, - // {translate: "confirm_no"} - // ] }; + } - this.settings = Immutable.Map( - merge(this.defaultSettings.toJS(), ss.get("settings_v3")) - ); - if (this.settings.get("themes") === "olDarkTheme") { - this.settings = this.settings.set("themes", "midnightTheme"); - } - let savedDefaults = ss.get("defaults_v1", {}); - /* Fix for old clients after changing cn to zh */ - if (savedDefaults && savedDefaults.locale) { - let cnIdx = savedDefaults.locale.findIndex(a => a === "cn"); - if (cnIdx !== -1) savedDefaults.locale[cnIdx] = "zh"; - } - if (savedDefaults && savedDefaults.themes) { - let olIdx = savedDefaults.themes.findIndex( - a => a === "olDarkTheme" - ); - if (olIdx !== -1) savedDefaults.themes[olIdx] = "midnightTheme"; + /** + * Checks if an object is actually empty (no keys or only empty keys) + * @param object + * @returns {boolean} + * @private + */ + _isEmpty(object) { + let isEmpty = true; + Object.keys(object).forEach(key => { + if (object.hasOwnProperty(key) && object[key] !== null) + isEmpty = false; + }); + return isEmpty; + } + + /** + * Ensures that defauls are not stored in local storage, only changes, and when reading inserts all defaults. + * + * @param mode + * @param settings + * @param defaultSettings + * @returns {{}} + * @private + */ + _replaceDefaults(mode = "saving", settings, defaultSettings = null) { + if (defaultSettings == null) { + // this method might be called recursively, so not always use the whole defaults + defaultSettings = this._getDefaultSetting(); } - this.defaults = merge({}, defaults, savedDefaults); + let excludedKeys = ["activeNode"]; - (savedDefaults.apiServer || []).forEach(api => { - let hasApi = false; - if (typeof api === "string") { - api = {url: api, location: null}; - } - this.defaults.apiServer.forEach(server => { - if (server.url === api.url) { - hasApi = true; + // avoid copy by reference + let returnSettings = {}; + if (mode === "saving") { + // remove every setting that is default + Object.keys(settings).forEach(key => { + if (excludedKeys.includes(key)) { + return; + } + // must be of same type to be compatible + if (typeof settings[key] === typeof defaultSettings[key]) { + // incompatible settings, dont store + if (typeof settings[key] == "object") { + let newSetting = this._replaceDefaults( + "saving", + settings[key], + defaultSettings[key] + ); + if (!this._isEmpty(newSetting)) { + returnSettings[key] = newSetting; + } + } else if (settings[key] !== defaultSettings[key]) { + // only save if its not the default + returnSettings[key] = settings[key]; + } } + // all other cases are defaults, do not put the value in local storage }); - - if (!hasApi) { - this.defaults.apiServer.push(api); - } - }); - - if ( - !savedDefaults || - (savedDefaults && - (!savedDefaults.apiServer || !savedDefaults.apiServer.length)) - ) { - for (let i = apiServer.length - 1; i >= 0; i--) { - let hasApi = false; - this.defaults.apiServer.forEach(api => { - if (api.url === apiServer[i].url) { - hasApi = true; + } else { + Object.keys(defaultSettings).forEach(key => { + let setDefaults = false; + if (settings[key] !== undefined) { + // exists in saved settings, check value + if (typeof settings[key] !== typeof defaultSettings[key]) { + // incompatible types, use default + setDefaults = true; + } else if (typeof settings[key] == "object") { + // check all subkeys + returnSettings[key] = this._replaceDefaults( + "loading", + settings[key], + defaultSettings[key] + ); + } else { + returnSettings[key] = settings[key]; } - }); - if (!hasApi) { - this.defaults.apiServer.unshift(apiServer[i]); + } else { + setDefaults = true; + } + if (setDefaults) { + if (typeof settings[key] == "object") { + // use defaults, deep copy + returnSettings[key] = JSON.parse( + JSON.stringify(defaultSettings[key]) + ); + } else { + returnSettings[key] = defaultSettings[key]; + } + } + }); + // copy all the rest as well + Object.keys(settings).forEach(key => { + if (returnSettings[key] == undefined) { + // deep copy + returnSettings[key] = JSON.parse( + JSON.stringify(settings[key]) + ); + } + }); + } + return returnSettings; + } + + /** + * Returns the currently active settings, either default or from local storage + * @returns {*} + * @private + */ + _getSetting() { + // migrate to new settings + // - v3 defaults are stored as values which makes it impossible to react on changed defaults + // - v4 refactored complete settings handling. defaults are no longer stored in local storage and + // set if not present on loading + let support_v3_until = new Date("2018-10-20T00:00:00Z"); + + if (!ss.has("settings_v4") && new Date() < support_v3_until) { + // ensure backwards compatibility of settings version + let settings_v3 = ss.get("settings_v3"); + if (!!settings_v3) { + if (settings_v3["themes"] === "olDarkTheme") { + settings_v3["themes"] = "midnightTheme"; } } + this._saveSettings(settings_v3, this._getDefaultSetting()); } - this.viewSettings = Immutable.Map(ss.get("viewSettings_v1")); + return this._loadSettings(); + } - this.marketDirections = Immutable.Map(ss.get("marketDirections")); + /** + * Overwrite configuration while utilizing call-by-reference + * @param apiTarget + * @param apiSource + * @private + */ + _injectApiConfiguration(apiTarget, apiSource) { + // any defaults in the apiConfig are to be maintained! + apiTarget.hidden = apiSource.hidden; + } - this.hiddenAssets = Immutable.List(ss.get("hiddenAssets", [])); - this.hiddenMarkets = Immutable.List(ss.get("hiddenMarkets", [])); + /** + * Save settings to local storage after checking for defaults + * @param settings + * @private + */ + _saveSettings(settings = null) { + if (settings == null) { + settings = this.settings.toJS(); + } + ss.set("settings_v4", this._replaceDefaults("saving", settings)); + } - this.apiLatencies = ss.get("apiLatencies", {}); + /** + * Load settings from local storage and fill in details + * @returns {{}} + * @private + */ + _loadSettings() { + let userSavedSettings = ss.get("settings_v4"); + // if (!!userSavedSettings) { + // console.log("User settings have been loaded:", userSavedSettings); + // } + return this._replaceDefaults("loading", userSavedSettings); + } - this.mainnet_faucet = ss.get( - "mainnet_faucet", - settingsAPIs.DEFAULT_FAUCET + /** + * Returns the currently active choices for settings, either default or from local storage + * @returns {*} + * @private + */ + _getChoices() { + // default choices the user can select from + let choices = this._getDefaultChoices(); + // get choices stored in local storage + let savedChoices = this._ensureBackwardsCompatibilityChoices( + ss.get("defaults_v1", {apiServer: []}) ); - this.testnet_faucet = ss.get( - "testnet_faucet", - settingsAPIs.TESTNET_FAUCET + + // merge choices by hand (do not use merge as the order in the apiServer list may change) + let mergedChoices = Object.assign({}, savedChoices); + Object.keys(choices).forEach(key => { + if (key != "apiServer") { + mergedChoices[key] = choices[key]; + } + }); + mergedChoices.apiServer = this._getApiServerChoices( + choices, + savedChoices ); + return mergedChoices; + } - this.exchange = fromJS(ss.get("exchange", {})); + /** + * Get all apiServer choices and mark the ones that are in the default choice as default + * @param choices + * @param savedChoices + * @returns {string} + * @private + */ + _getApiServerChoices(choices, savedChoices) { + let apiServer = choices.apiServer.slice(0); // maintain order in apiConfig.js + // add any apis that the user added and update changes + savedChoices.apiServer.forEach(api => { + let found = apiServer.find(a => a.url == api.url); + if (!!found) { + this._injectApiConfiguration(found, api); + } else { + if (!api.default) { + // always add personal nodes at end of existing nodes, arbitrary decision + apiServer.push(api); + } + } + }); + apiServer = apiServer.map(node => { + let found = choices.apiServer.find(a => a.url == node.url); + node.default = !!found; + node.hidden = !!node.hidden; // make sure this flag exists + return node; + }); + return apiServer; + } + + /** + * Adjust loaded choices for backwards compatibility if any key names or values change + * @param savedChoices + * @returns {*} + * @private + */ + _ensureBackwardsCompatibilityChoices(savedChoices) { + /* Fix for old clients after changing cn to zh */ + if (savedChoices && savedChoices.locale) { + let cnIdx = savedChoices.locale.findIndex(a => a === "cn"); + if (cnIdx !== -1) savedChoices.locale[cnIdx] = "zh"; + } + if (savedChoices && savedChoices.themes) { + let olIdx = savedChoices.themes.findIndex(a => a === "olDarkTheme"); + if (olIdx !== -1) savedChoices.themes[olIdx] = "midnightTheme"; + } + if (savedChoices && savedChoices.apiServer) { + savedChoices.apiServer = savedChoices.apiServer.map(api => { + // might be only a string, be backwards compatible + if (typeof api === "string") { + api = { + url: api, + location: null + }; + } + return api; + }); + } + return savedChoices; } init() { @@ -256,8 +472,7 @@ class SettingsStore { } onChangeSetting(payload) { - this.settings = this.settings.set(payload.setting, payload.value); - + let save = true; switch (payload.setting) { case "faucet_address": if (payload.value.indexOf("testnet") === -1) { @@ -269,23 +484,34 @@ class SettingsStore { } break; - case "apiServer": - let faucetUrl = - payload.value.indexOf("testnet") !== -1 - ? this.testnet_faucet - : this.mainnet_faucet; - this.settings = this.settings.set("faucet_address", faucetUrl); - break; - case "walletLockTimeout": ss.set("lockTimeout", payload.value); break; + case "activeNode": + // doesnt need to be saved in local storage + save = true; + default: break; } - ss.set("settings_v3", this.settings.toJS()); + // check current settings + if (this.settings.get(payload.setting) !== payload.value) { + this.settings = this.settings.set(payload.setting, payload.value); + if (save) { + this._saveSettings(); + } + } + // else { + // console.warn( + // "Trying to save unchanged value (" + + // payload.setting + + // ": " + + // payload.value + + // "), consider refactoring to avoid this" + // ); + // } } onChangeViewSetting(payload) { @@ -401,9 +627,10 @@ class SettingsStore { onClearSettings(resolve) { ss.remove("settings_v3"); + ss.remove("settings_v4"); this.settings = this.defaultSettings; - ss.set("settings_v3", this.settings.toJS()); + this._saveSettings(); if (resolve) { resolve(); From 54e39499c004402f364b370ac171e60dd98829c6 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Thu, 26 Jul 2018 11:30:25 +0200 Subject: [PATCH 27/69] #1712: Improve find market search results --- app/components/Exchange/MyMarkets.jsx | 68 +++++++++++++++------------ 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/app/components/Exchange/MyMarkets.jsx b/app/components/Exchange/MyMarkets.jsx index 7a2f4654b8..1a83293844 100644 --- a/app/components/Exchange/MyMarkets.jsx +++ b/app/components/Exchange/MyMarkets.jsx @@ -1037,25 +1037,33 @@ class MyMarkets extends React.Component { )}
      - {!myMarketTab && !this.state.inputValue - ? null - : preferredBases.map((base, index) => { - if (!base) return null; - return ( -
    • - {base} -
    • - ); - })} + {myMarketTab && + preferredBases.map((base, index) => { + if (!base) return null; + return ( +
    • + {base} +
    • + ); + })} + {!myMarketTab ? ( +
    • + {this.state.activeFindBase} +
    • + ) : null} {myMarketTab && hasOthers ? (
    • { - ZfApi.publish("quote_selection", "open"); - }} - className="mymarkets-tab" - > -  +  -
    • + {myMarketTab && ( +
    • { + ZfApi.publish("quote_selection", "open"); + }} + className="mymarkets-tab" + > +  +  +
    • + )}
    Date: Thu, 26 Jul 2018 11:33:56 +0200 Subject: [PATCH 28/69] Fix #1712: Add OPEN.EOSDAC asset to default lists --- app/branding.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/branding.js b/app/branding.js index 5d71b33920..cdbf7bb30f 100644 --- a/app/branding.js +++ b/app/branding.js @@ -136,6 +136,7 @@ export function getMyMarketsQuotes() { "OPEN.WAVES", "OPEN.ZEC", "OPEN.ZRX", + "OPEN.EOSDAC", "PPY", "RUBLE", "RUDEX.DCT", @@ -174,6 +175,7 @@ export function getFeaturedMarkets() { ["USD", "GDEX.ETH"], ["USD", "GDEX.EOS"], ["USD", "GDEX.BTO"], + ["USD", "OPEN.EOSDAC"], ["CNY", "BTS"], ["CNY", "OPEN.BTC"], ["CNY", "USD"], @@ -208,6 +210,7 @@ export function getFeaturedMarkets() { ["BTS", "GDEX.ETH"], ["BTS", "GDEX.EOS"], ["BTS", "GDEX.BTO"], + ["BTS", "OPEN.EOSDAC"], ["KAPITAL", "OPEN.BTC"], ["USD", "OPEN.STEEM"], ["USD", "OPEN.MAID"], From 6277df6a68b733cc7c014cf862459fccf1eb17e1 Mon Sep 17 00:00:00 2001 From: ety001 Date: Fri, 27 Jul 2018 15:17:37 +0800 Subject: [PATCH 29/69] Update bts.to0l.cn API node information (#1730) update bts.to0l.cn information. --- app/api/apiConfig.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index 06b0fdbf59..e7a88157a8 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -210,7 +210,14 @@ export const settingsAPIs = { operator: "Witness: clockwork", contact: "telegram:clockworkgr" }, - {url: "wss://bts.to0l.cn:4443/ws", location: "China"}, + { + url: "wss://bts.to0l.cn:4443/ws", + region: "Eastern Asia", + country: "China", + location: "Shandong", + operator: "Witness: liuye", + contact: "email:work@liuye.tech" + }, {url: "wss://btsfullnode.bangzi.info/ws", location: "Germany"}, // Testnet { From f617a4911f50c74ec0b4195c9f2461b0b8920b15 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Fri, 27 Jul 2018 09:42:09 +0200 Subject: [PATCH 30/69] Update react-tooltip --- package-lock.json | 38 +++----------------------------------- package.json | 2 +- 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03a9173b93..1763146740 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16105,22 +16105,6 @@ "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.0" - }, - "dependencies": { - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - } } }, "react-autocomplete": { @@ -16177,22 +16161,6 @@ "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.0" - }, - "dependencies": { - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - } } }, "react-foundation-apps": { @@ -16535,9 +16503,9 @@ } }, "react-tooltip": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.6.0.tgz", - "integrity": "sha512-Ru/UAaD6raLfJi+IiBcWUvGoV0kns55ZiPa1hVn+LI7NlHKrxENJj6TlKtLWIL/KF4Y44QjLzqmWKnFUP9gWGQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.6.1.tgz", + "integrity": "sha512-4NVjHNIx1ZazFYBNP044DHW0cr95Qaq0DSwWbrEQ7VyE8AxemHDjp0DoYvV8wilK9vR9jMlSwDW6ebRgbk3aHw==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.6.0" diff --git a/package.json b/package.json index 0fc6d8a9bb..c6b66895a9 100644 --- a/package.json +++ b/package.json @@ -181,7 +181,7 @@ "react-responsive-mixin": "^0.4.0", "react-router-dom": "^4.3.1", "react-scroll": "^1.7.9", - "react-tooltip": "^3.2.2", + "react-tooltip": "^3.6.1", "react-transition-group": "^1.2.0", "react-translate-component": "^0.15.1", "steem-js-api": "^0.7.1", From 59e3a4ec4c0dcb3661605c49b8d40c22fd9664e4 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Fri, 27 Jul 2018 09:42:52 +0200 Subject: [PATCH 31/69] Fix #1723: Clean up proxy input field, add tooltips --- app/assets/locales/locale-de.json | 5 +++++ app/assets/locales/locale-en.json | 5 +++++ app/assets/locales/locale-es.json | 5 +++++ app/assets/locales/locale-fr.json | 5 +++++ app/assets/locales/locale-it.json | 5 +++++ app/assets/locales/locale-ja.json | 5 +++++ app/assets/locales/locale-ko.json | 5 +++++ app/assets/locales/locale-ru.json | 5 +++++ app/assets/locales/locale-tr.json | 5 +++++ app/assets/locales/locale-zh.json | 5 +++++ app/components/Account/AccountSelector.jsx | 2 +- app/components/Account/AccountVoting.jsx | 11 ++++++++--- 12 files changed, 59 insertions(+), 4 deletions(-) diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index c59e6ef4cb..bd93de6765 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -370,6 +370,7 @@ "remove_committee": "Entfernen", "remove_witness": "Entfernen", "save_finish": "Click save to finish", + "set_proxy": "Set a proxy here", "start": "Start Datum", "status": { "neutral": "Neutral", @@ -1580,6 +1581,10 @@ "propose_scam": "This proposal was created by a known scammer, do not approve it!", "propose_tip": "Propose another user to initiate a transaction", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Settling will let you convert your holdings of %(asset)s to BTS after a delay of 24 hours, at a price equal to the feed price at that time.", "settle_price": diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index e12d065c78..58030160a6 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -366,6 +366,7 @@ "remove_committee": "Remove", "remove_witness": "Remove", "save_finish": "Click save to finish", + "set_proxy": "Set a proxy here", "start": "Start date", "status": { "neutral": "Neutral", @@ -1578,6 +1579,10 @@ "propose_scam": "This proposal was created by a known scammer, do not approve it!", "propose_tip": "Propose another user to initiate a transaction", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Settling will let you convert your holdings of %(asset)s to BTS after a delay of 24 hours, at a price equal to the feed price at that time.", "settle_price": diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index a8f64aec70..4c171e1a7c 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -375,6 +375,7 @@ "remove_committee": "Remover", "remove_witness": "Remover", "save_finish": "Haga clic en guardar para finalizar", + "set_proxy": "Set a proxy here", "start": "Fecha de inicio", "status": { "neutral": "Neutral", @@ -1607,6 +1608,10 @@ "propose_scam": "¡Esta propuesta fue creada por un estafador conocido, no la aprueba!", "propose_tip": "Proponer otro usuario para iniciar una transacción", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "El settling te permitirá de convertir tus propriedades de %(asset)s en BTS después de un retraso de 24 horas, a un precio igual al precio dado en ese momento.", "settle_price": diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index 9900d737b9..68df451b44 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -366,6 +366,7 @@ "remove_committee": "Remove", "remove_witness": "Remove", "save_finish": "Click save to finish", + "set_proxy": "Set a proxy here", "start": "Start date", "status": { "neutral": "Neutral", @@ -1577,6 +1578,10 @@ "propose_scam": "This proposal was created by a known scammer, do not approve it!", "propose_tip": "Propose another user to initiate a transaction", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Settling will let you convert your holdings of %(asset)s to BTS after a delay of 24 hours, at a price equal to the feed price at that time.", "settle_price": diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index 87b3c078f7..5c5fbaca00 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -373,6 +373,7 @@ "remove_committee": "Rimuovi", "remove_witness": "Rimuovi", "save_finish": "Clicca Salva per completare", + "set_proxy": "Set a proxy here", "start": "Data inizio", "status": { "neutral": "Neutrale", @@ -1602,6 +1603,10 @@ "propose_scam": "Questa proposta è stata creata da un noto ciarlatano, non approvarla!", "propose_tip": "Propose another user to initiate a transaction", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Il settling ti permetterà di convertire le tue disponibilità di %(asset)s in BTS dopo un'attesa di 24 ore, ad un prezzo uguale al prezzo di mercato in quel momento.", "settle_price": diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index 4a46945cdc..be17809353 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -363,6 +363,7 @@ "remove_committee": "削除", "remove_witness": "削除", "save_finish": "Click save to finish", + "set_proxy": "Set a proxy here", "start": "開始日", "status": { "neutral": "中立", @@ -1578,6 +1579,10 @@ "propose_scam": "この提案は有名な詐欺師によるものです。応じないでください!", "propose_tip": "別のユーザーからトランザクションを提案する", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "精算により、保有する%(asset)sを24時間の遅延後にBTSにその時点のフィード価格で変換できます。", "settle_price": "これは決済注文を実行する価格です。", diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index 811dcc0f19..9a4e9211f0 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -366,6 +366,7 @@ "remove_committee": "제거", "remove_witness": "제거", "save_finish": "Click save to finish", + "set_proxy": "Set a proxy here", "start": "Start date", "status": { "neutral": "Neutral", @@ -1572,6 +1573,10 @@ "propose_scam": "This proposal was created by a known scammer, do not approve it!", "propose_tip": "Propose another user to initiate a transaction", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Settling will let you convert your holdings of %(asset)s to BTS after a delay of 24 hours, at a price equal to the feed price at that time.", "settle_price": diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index 72486c8f85..4ead8ebdee 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -376,6 +376,7 @@ "remove_committee": "Удалить", "remove_witness": "Удалить", "save_finish": "Нажмите кнопку \"Сохранить\", чтобы закончить", + "set_proxy": "Set a proxy here", "start": "Дата начала", "status": { "neutral": "Нейтральные", @@ -1611,6 +1612,10 @@ "Это предложение было создано известным мошенником, не подтверждайте его!", "propose_tip": "Предложить другому пользователю инициировать транзакцию", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Погашение позволит Вам обменять Ваши %(asset)s на BTS с задержкой в 24 часа по цене, равной цене котировки на момент погашения.", "settle_price": diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index d9cc78a1a7..9c5db6ae26 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -369,6 +369,7 @@ "remove_committee": "Kaldır", "remove_witness": "Kaldır", "save_finish": "Click save to finish", + "set_proxy": "Set a proxy here", "start": "Başlangıç tarihi", "status": { "neutral": "Tarafsız", @@ -1590,6 +1591,10 @@ "propose_scam": "Bu işlem teklifi bilinen bir dolandırıcı tarafından sunulmuştur, onaylamayın!", "propose_tip": "Propose another user to initiate a transaction", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "Sona erdirme işlemi dijital varlıklarınızı 24 saatlik bir gecikme ile o anki fiyat üzerinden BTS'ye dönüştürmenizi sağlar", "settle_price": "Sona erdirilen emirlerin gerçekleşeceği fiyat", diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index f4af00c913..d63c7a7009 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -353,6 +353,7 @@ "remove_committee": "移除", "remove_witness": "移除", "save_finish": "点击“保存修改”完成投票", + "set_proxy": "Set a proxy here", "start": "开始时间", "status": { "neutral": "中立", @@ -1525,6 +1526,10 @@ "over_limit": "此桥接服务没有足够的资产来完成此订单。", "propose_scam": "该提案发起人是已知的诈骗嫌疑人,请不要批准该提案!", "propose_tip": "提议另一个用户发起交易", + "proxy_remove": + "You have a proxy set, to remove it simply clear this input field", + "proxy_search": + "Search for an account to be used as your proxy for voting", "settle": "使用清算功能,你可以在24小时后以当时的清算价将你的 %(asset)s 资产转换为对应抵押资产", "settle_price": "清算单执行时将使用的价格", diff --git a/app/components/Account/AccountSelector.jsx b/app/components/Account/AccountSelector.jsx index f86b2a885d..aef65dbf46 100644 --- a/app/components/Account/AccountSelector.jsx +++ b/app/components/Account/AccountSelector.jsx @@ -366,7 +366,7 @@ class AccountSelector extends React.Component { {useHR &&
    }
    ) : null} -
    +
    {account && account.accountType === "pubkey" ? (
    diff --git a/app/components/Account/AccountVoting.jsx b/app/components/Account/AccountVoting.jsx index 1bb9d77ccb..e5428b5127 100644 --- a/app/components/Account/AccountVoting.jsx +++ b/app/components/Account/AccountVoting.jsx @@ -684,18 +684,23 @@ class AccountVoting extends React.Component { onChange={this.onProxyChange.bind(this)} onAccountChanged={this.onProxyAccountFound} tabIndex={1} - placeholder="Proxy not set" + placeholder={counterpart.translate("account.votes.set_proxy")} + tooltip={counterpart.translate( + !this.state.proxy_account_id + ? "tooltip.proxy_search" + : "tooltip.proxy_remove" + )} hideImage > - + Date: Fri, 27 Jul 2018 10:13:01 +0200 Subject: [PATCH 32/69] Fix #1706: Update scam accounts list --- app/lib/common/account_utils.js | 49 +------ app/lib/common/scamAccounts.js | 251 ++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 44 deletions(-) create mode 100644 app/lib/common/scamAccounts.js diff --git a/app/lib/common/account_utils.js b/app/lib/common/account_utils.js index 0ca83d9c5a..62aafb49f4 100644 --- a/app/lib/common/account_utils.js +++ b/app/lib/common/account_utils.js @@ -2,6 +2,11 @@ import {ChainStore} from "bitsharesjs"; import utils from "./utils"; import counterpart from "counterpart"; import {estimateFee} from "./trxHelper"; +import { + scamAccountsPolo, + scamAccountsBittrex, + scamAccountsOther +} from "./scamAccounts"; export default class AccountUtils { /** @@ -99,50 +104,6 @@ export default class AccountUtils { } static isKnownScammer(account) { - const scamAccountsPolo = [ - "polonie-wallet", - "polonie-xwallet", - "poloniewallet", - "poloniex-deposit", - "poloniex-wallet", - "poloniexwall-et", - "poloniexwallett", - "poloniexwall-t", - "poloniexwalle", - "poloniex", - "poloneix" - ]; - - const scamAccountsBittrex = [ - "bittrex-deopsit", - "bittrex-deposi", - "bittrex-depositt", - "bittrex-dposit", - "bittrex", - "bittrex-deposits" - ]; - - const scamAccountsOther = [ - "coinbase", - "blocktrade", - "locktrades", - "yun.bts", - "transwiser-walle", - "transwiser-wallets", - "ranswiser-wallet", - "yun.btc", - "pay.coinbase.com", - "pay.bts.com", - "btc38.com", - "yunbi.com", - "aex-bts-deposit-walle", - "coinbase.com", - "ripple.com", - "livecoi-net", - "livecoin.net", - "livecoinnet" - ]; - let scamMessage = null; if (scamAccountsPolo.indexOf(account) !== -1) { scamMessage = counterpart.translate("account.polo_scam"); diff --git a/app/lib/common/scamAccounts.js b/app/lib/common/scamAccounts.js new file mode 100644 index 0000000000..0c404453db --- /dev/null +++ b/app/lib/common/scamAccounts.js @@ -0,0 +1,251 @@ +export const scamAccountsPolo = [ + "polonie-wallet", + "polonie-xwallet", + "poloniewallet", + "poloniex-deposit", + "poloniex-wallet", + "poloniexwall-et", + "poloniexwallett", + "poloniexwall-t", + "poloniexwalle", + "poloniex", + "poloneix" +]; + +export const scamAccountsBittrex = [ + "bittrex-deopsit", + "bittrex-deposi", + "bittrex-depositt", + "bittrex-dposit", + "bittrex", + "bittrex-deposits" +]; + +export const scamAccountsOther = [ + "gateio", + "zbeoscharge1", + "pxneosincome", + "binance-btc-1", + "huobipro", + "bitpal", + "trueusd", + "zbbtc", + "bcos", + "coinegg.main", + "xbrick", + "xbrick.cny", + "xbrick.usd", + "xbrick.btc", + "coinw", + "lakebtc", + "coinexchange", + "xbtce", + "kucoin", + "quadrigacx", + "neraex", + "topbtc", + "abucoins", + "coinut", + "fargobase", + "coinmate", + "nevbit", + "coinbene", + "bitpie", + "electrum", + "arcbit", + "armory", + "msigna", + "coldlar", + "binance-bts-l", + "binance-bts-i", + "coinex", + "qcash", + "uncoinex", + "poim", + "bbex", + "otcx", + "u-coin", + "kkcoin", + "kkcoinwallet", + "kkcoin.wallet", + "jaxx", + "bitbill", + "antpool", + "swftc", + "swftcoin", + "aida", + "secp256k1", + "bjex", + "www.binance.com", + "coinex.com", + "www.coinex.com", + "coin900", + "kcash", + "cointobe", + "otcbtc", + "winex.pro", + "btsid", + "zhaobi", + "coincode", + "yobtc", + "bitoex", + "ctpmall", + "top.one", + "ddex", + "dragonex", + "geth", + "cex.com", + "coinw.com", + "baseline", + "wirex", + "chaoex.com", + "ourdax", + "exx.com", + "bitvip.com", + "myetherwallet", + "atoken", + "beechat", + "keepkey", + "mycelium", + "greenbits", + "coin.space", + "greenaddress", + "changelly", + "bepal", + "bitcoinindonesi", + "erc721", + "erc-20", + "erc-721", + "cryptobridg", + "changenow", + "coincoming", + "coin900.com", + "door.one", + "bibox.com", + "lbank.info", + "hotbit", + "qbao", + "expie", + "expie.com", + "eip20", + "eip-20", + "eos.bts", + "eos.btc", + "bts.eos", + "btc.eos", + "zhaobi.com", + "www.zhaobi.com", + "licai.deposit", + "zeniex", + "richcore", + "richcore.com", + "digitaex", + "safewallet", + "tdax", + "tdax.com", + "cointome", + "bigether", + "bigether.vip", + "dexko", + "oex.com", + "hadax", + "www.hadax.com", + "hadax.com", + "cohescure", + "ico-china", + "icoape", + "icoape.com", + "coinbig", + "coinbig.com", + "bitspark-hold", + "gate-io-bt", + "ate-io-bts", + "geta-io-bts", + "yyex", + "yyex.com", + "www.yyex.com", + "yex.com", + "litepay", + "onchainfx.com", + "mycrypto", + "eosfinix", + "cobo", + "rootoken", + "bitpesa", + "cointopay", + "decred", + "wazirx", + "gate-io-b", + "palmpay", + "coinstocks", + "blind", + "blind-transfer", + "stealth", + "bithd", + "cryptobridge-payout", + "zbsen", + "bits.farm", + "bitsfarm", + "idex.market", + "idex", + "etherflyer", + "etherflyer.com", + "tcash", + "dewone", + "stex.exchange", + "stex", + "tokenxx", + "qtum-electrum", + "p2pbucks", + "forkdelta", + "bitsblockchain", + "bitinka", + "ethfinex", + "neraex.pro", + "simex.global", + "topbtc.com", + "btcmarkets.net", + "coinrail", + "lakebtc.com", + "vebitcoin", + "bancor.network", + "btc-alpha.com", + "stronghold", + "tradebytrade.com", + "tradebytrade", + "mercadobitcoin", + "koineks.com", + "bitonic", + "coinut.com", + "bitcointrade", + "koinim.com", + "bitun", + "coinbell", + "more.top", + "issuer", + "ls123", + "mai1100", + "hackers", + "aex-bitcny-deposit", + "btsmoney", + "n0stradumpus", + "binancecleos", + "coinbase", + "blocktrade", + "locktrades", + "yun.bts", + "transwiser-walle", + "transwiser-wallets", + "ranswiser-wallet", + "yun.btc", + "pay.coinbase.com", + "pay.bts.com", + "btc38.com", + "yunbi.com", + "aex-bts-deposit-walle", + "coinbase.com", + "ripple.com", + "livecoi-net", + "livecoin.net", + "livecoinnet" +]; From adc8a8a80c003983c5868fda5d8c01008824c17d Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Fri, 27 Jul 2018 10:58:19 +0200 Subject: [PATCH 33/69] Fix #1550: Make preferred units depend on the network (main/testnet) --- app/actions/SettingsActions.js | 4 ++++ app/branding.js | 6 ++++-- app/stores/SettingsStore.js | 23 ++++++++++++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/app/actions/SettingsActions.js b/app/actions/SettingsActions.js index c86a7ade4d..a4ac53b953 100644 --- a/app/actions/SettingsActions.js +++ b/app/actions/SettingsActions.js @@ -76,6 +76,10 @@ class SettingsActions { modifyPreferedBases(payload) { return payload; } + + updateUnits() { + return true; + } } export default alt.createActions(SettingsActions); diff --git a/app/branding.js b/app/branding.js index cdbf7bb30f..fb173f3691 100644 --- a/app/branding.js +++ b/app/branding.js @@ -64,8 +64,10 @@ export function getDefaultLogin() { * * @returns {[string,string,string,string,string,string]} */ -export function getUnits() { - return ["BTS", "USD", "CNY", "BTC", "EUR", "GBP"]; +export function getUnits(chainId = "4018d784") { + if (chainId === "4018d784") + return ["BTS", "USD", "CNY", "BTC", "EUR", "GBP"]; + else if (chainId === "39f5e2ed") return ["TEST"]; } /** diff --git a/app/stores/SettingsStore.js b/app/stores/SettingsStore.js index 64088dbfcb..3bcafe7b5c 100644 --- a/app/stores/SettingsStore.js +++ b/app/stores/SettingsStore.js @@ -52,7 +52,8 @@ class SettingsStore { onSwitchLocale: IntlActions.switchLocale, onSetUserMarket: SettingsActions.setUserMarket, onUpdateLatencies: SettingsActions.updateLatencies, - onModifyPreferedBases: SettingsActions.modifyPreferedBases + onModifyPreferedBases: SettingsActions.modifyPreferedBases, + onUpdateUnits: SettingsActions.updateUnits }); this.initDone = false; @@ -130,7 +131,7 @@ class SettingsStore { "ja" ], apiServer: settingsAPIs.WS_NODE_LIST.slice(0), // clone all default servers as configured in apiConfig.js - unit: getUnits(), + unit: getUnits(this._getChainId()), showSettles: [{translate: "yes"}, {translate: "no"}], showAssetPercent: [{translate: "yes"}, {translate: "no"}], themes: ["darkTheme", "lightTheme", "midnightTheme"], @@ -424,6 +425,11 @@ class SettingsStore { markets_39f5e2ed: "TEST" }; let coreAsset = coreAssets[this.starredKey] || "BTS"; + /* + * Update units depending on the chain, also make sure the 0 index + * asset is always the correct CORE asset name + */ + this.onUpdateUnits(); this.defaults.unit[0] = coreAsset; let defaultBases = bases[this.starredKey] || bases.markets_4018d784; @@ -641,8 +647,12 @@ class SettingsStore { this.onChangeSetting({setting: "locale", value: locale}); } + _getChainId() { + return (Apis.instance().chain_id || "4018d784").substr(0, 8); + } + _getChainKey(key) { - const chainId = Apis.instance().chain_id; + const chainId = this._getChainId(); return key + (chainId ? `_${chainId.substr(0, 8)}` : ""); } @@ -707,6 +717,13 @@ class SettingsStore { ss.set(this.basesKey, this.preferredBases.toArray()); } + + onUpdateUnits() { + this.defaults.unit = getUnits(this._getChainId()); + if (this.defaults.unit.indexOf(this.settings.get("unit")) === -1) { + this.settings = this.settings.set("unit", this.defaults.unit[0]); + } + } } export default alt.createStore(SettingsStore, "SettingsStore"); From 5800def7a1fc68fd755a228b21d1e63628d8663b Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Mon, 30 Jul 2018 12:18:01 +0200 Subject: [PATCH 34/69] Fix #1598: Add fee pool claim and cleanup Asset page --- app/actions/AssetActions.js | 26 ++++ app/assets/locales/locale-de.json | 7 + app/assets/locales/locale-en.json | 9 +- app/assets/locales/locale-es.json | 7 + app/assets/locales/locale-fr.json | 7 + app/assets/locales/locale-it.json | 7 + app/assets/locales/locale-ja.json | 7 + app/assets/locales/locale-ko.json | 7 + app/assets/locales/locale-ru.json | 7 + app/assets/locales/locale-tr.json | 7 + app/assets/locales/locale-zh.json | 7 + app/assets/stylesheets/_shame.scss | 6 + app/components/Account/AccountAssetUpdate.jsx | 4 +- .../{FundFeePool.jsx => FeePoolOperation.jsx} | 132 ++++++++++++++++-- app/components/Blockchain/Asset.jsx | 97 +++++++++---- 15 files changed, 292 insertions(+), 45 deletions(-) rename app/components/Account/{FundFeePool.jsx => FeePoolOperation.jsx} (57%) diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index 99d1a1a1a7..38b55022e2 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -37,6 +37,32 @@ class AssetActions { }; } + claimPool(asset, amount) { + let tr = WalletApi.new_transaction(); + tr.add_type_operation("asset_claim_pool", { + fee: { + amount: 0, + asset_id: "1.3.0" + }, + issuer: asset.get("issuer"), + asset_id: asset.get("id"), + amount_to_claim: amount.toObject() + }); + return dispatch => { + return WalletDb.process_transaction(tr, null, true) + .then(() => { + dispatch(true); + }) + .catch(error => { + console.log( + "[AssetActions.js:150] ----- claimPool error ----->", + error + ); + dispatch(false); + }); + }; + } + updateFeedProducers(account, asset, producers) { let tr = WalletApi.new_transaction(); tr.add_type_operation("asset_update_feed_producers", { diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index bd93de6765..d97581c164 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -623,13 +623,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Gebühren beanspruchen", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "Der Asset-Herausgeber kann die zusammengetragenen Anteile hier beanspruchen", "core_exchange_rate": "Kernhandelsrate", + "fund": "Fund the fee pool", "fund_text": "Der Gebührenpool wird dazu genutzt Gebühren in %(core)s durch einen impliziten Wechsel von %(asset)s zu %(core)s zu finanzieren. Sollte der Gebührenpool trocken liegen, können Gebühren nicht länger in %(asset)s bezahlt werden sondern nur noch in %(core)s", "pool_balance": "Pool-Guthaben", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Fee Pool", "unclaimed_issuer_income": "Nicht ausgezahlte Herausgeberanteile" @@ -1698,6 +1704,7 @@ "account_whitelist": "Konto-Positivliste", "all": "Show all", "assert": "Operation bestätigen", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Gebühr für 'Asset beanspruchen'", "asset_claim_pool": "Claim asset fee pool", "asset_create": "Asset erstellen", diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 58030160a6..e0a197adba 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -619,13 +619,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Claim fees", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "The asset issuer may claim any accumulated fees here.", "core_exchange_rate": "Core exchange rate (CER)", + "fund": "Fund the fee pool", "fund_text": - "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s", + "Anyone can add %(core)s to the fee pool balance using this form:", "pool_balance": "Pool balance", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, @@ -1695,6 +1701,7 @@ "account_whitelist": "Account whitelist", "all": "Show all", "assert": "Assert operation", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Claim asset fees", "asset_claim_pool": "Claim asset fee pool", "asset_create": "Create asset", diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index 4c171e1a7c..7cbad12260 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -631,13 +631,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Reclamar tarifas", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "El emisor del activo puede reclamar cualquier comisiòn acumulada aquí.", "core_exchange_rate": "Core exchange rate (CER)", + "fund": "Fund the fee pool", "fund_text": "El conjunto de comisiones se usa para pagar tarifas en %(core)s convirtiendo la comisiòn en %(asset)s a %(core)s. Si la comisiòn de la piscina se queda sin fondos, las comisiones ya no se pueden pagar en %(asset)s y seran el predeterminada a %(core)s", "pool_balance": "Balance del Fondo", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Fondo de Comisiones", "unclaimed_issuer_income": "Ingresos del emisor no reclamados" }, @@ -1726,6 +1732,7 @@ "account_whitelist": "Lista blanca", "all": "Mostrar todo", "assert": "Afirmar operación", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Reclamar comisiones de activos", "asset_claim_pool": "Claim asset fee pool", "asset_create": "Crear activo", diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index 68df451b44..ec7c3d5df0 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -619,13 +619,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Claim fees", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "The asset issuer may claim any accumulated fees here.", "core_exchange_rate": "Core exchange rate (CER)", + "fund": "Fund the fee pool", "fund_text": "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s", "pool_balance": "Pool balance", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, @@ -1695,6 +1701,7 @@ "account_whitelist": "Whiteliste de compte", "all": "Show all", "assert": "Assert operation", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Claim asset fees", "asset_claim_pool": "Claim asset fee pool", "asset_create": "Creation d'actif", diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index 5c5fbaca00..ec982a3cfa 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -629,13 +629,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Riscuoti commissioni", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "L'erogatore dell'asset può riscuotere qui eventuali commissioni accumulate.", "core_exchange_rate": "Core exchange rate (CER)", + "fund": "Fund the fee pool", "fund_text": "Il fee pool è usato per pagare le commissioni in %(core)s convertendo automaticamente le commissioni in %(asset)s a %(core)s. Se il fee pool esaurisce i fondi, le commissioni non possono più essere pagate in %(asset)s e saranno di default in %(core)s", "pool_balance": "Saldo del pool", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Fee Pool", "unclaimed_issuer_income": "Reddito dell'erogatore non riscosso" }, @@ -1722,6 +1728,7 @@ "account_whitelist": "Whitelist account", "all": "Mostra tutti", "assert": "Assert operation", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Riscuoti le commissioni dell'asset", "asset_claim_pool": "Claim asset fee pool", "asset_create": "Crea asset", diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index be17809353..3ce5717fe7 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -619,13 +619,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "手数料を請求", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "アセット発行者はここに蓄積された手数料を請求することができます。", "core_exchange_rate": "中心取引レート (CER)", + "fund": "Fund the fee pool", "fund_text": "手数料プールは%(asset)sの手数料を%(core)sに換算することによって%(core)sの手数料を支払うために使用されます。手数料プールの資金が尽きた場合、手数料を%(asset)sで払うことはできなくなり、既定値は%(core)sになります。", "pool_balance": "プール残高", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "手数料プール", "unclaimed_issuer_income": "未請求の発行者収入" }, @@ -1695,6 +1701,7 @@ "account_whitelist": "アカウントホワイトリスト", "all": "すべて表示", "assert": "アサート操作", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "アセット手数料を請求", "asset_claim_pool": "Claim asset fee pool", "asset_create": "アセットを作成", diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index 9a4e9211f0..ff7a0313f6 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -619,13 +619,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Claim fees", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "The asset issuer may claim any accumulated fees here.", "core_exchange_rate": "Core exchange rate", + "fund": "Fund the fee pool", "fund_text": "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s", "pool_balance": "풀 잔고", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, @@ -1689,6 +1695,7 @@ "account_whitelist": "계정 화이트리스트", "all": "Show all", "assert": "Assert operation", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Claim asset fees", "asset_claim_pool": "Claim asset fee pool", "asset_create": "자산 생성", diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index 4ead8ebdee..aa967936b0 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -633,13 +633,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Потребовать комиссию", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "Эмитент активов может востребовать любую из накопленных здесь комиссий.", "core_exchange_rate": "Основной обменный курс (CER)", + "fund": "Fund the fee pool", "fund_text": "Комиссионный пул платит в %(core)s, конвертируя комиссию из %(asset)s в %(core)s. Если в пуле недостаточно средств, комиссии могут не выплачиваться в %(asset)s, а будут по умолчанию в %(core)s", "pool_balance": "Баланс пула", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Пул комиссии", "unclaimed_issuer_income": "Невостребованный доход эмитента\n" }, @@ -1729,6 +1735,7 @@ "account_whitelist": "Добавление в белый список", "all": "Показать все", "assert": "Операция подтверждения", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Взыскание комиссий с активов", "asset_claim_pool": "Востребовать пул комиссий актива", "asset_create": "Создание актива", diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index 9c5db6ae26..57d69805cf 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -625,13 +625,19 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "Ücretleri talep et", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "Dijital varlık sahibi burada biriken ücretleri talep edebilir.", "core_exchange_rate": "Esas Kur (CER)", + "fund": "Fund the fee pool", "fund_text": "Ücret havuzu %(asset)s olarak ödenen işlem ücretlerini %(core)s'e çevirerek ödemek için kullanılır. Eğer ücret havuzunda para kalmazsa, ücretler artık %(asset)s olarak ödenemez ve %(core)s kullanılır ", "pool_balance": "Havuz bakiyesi", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "Ücret Havuzu", "unclaimed_issuer_income": "Talep edilmemiş ihraççı geliri" }, @@ -1707,6 +1713,7 @@ "account_whitelist": "İzin Listesine Alma", "all": "Tümünü göster", "assert": "İşlem beyanı", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "Aktif ücretlerini talep et", "asset_claim_pool": "Claim asset fee pool", "asset_create": "Yeni Oluştur", diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index d63c7a7009..cf8d27bbe8 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -602,12 +602,18 @@ }, "asset": { "fee_pool": { + "claim_balance": "Claim fee pool balance", "claim_fees": "领取手续费", + "claim_pool_text": + "The asset owner may withdraw funds from the fee pool using this form:", "claim_text": "资产发行人可以在这里领取累积的资产手续费。", "core_exchange_rate": "手续费汇率", + "fund": "Fund the fee pool", "fund_text": "所有网络手续费最终将使用 %(core)s 进行支付。手续费资金池用来承担从 %(asset)s 转换为 %(core)s 的费用,以便用户可以使用 %(asset)s 来支付手续费。如果资金池中余额用完,用户将无法继续使用 %(asset)s 支付手续费。", "pool_balance": "资金池余额", + "pool_text": + "The fee pool is used to pay fees in %(core)s by converting the fee in %(asset)s to %(core)s. If the fee pool runs out of funds, fees may no longer be paid in %(asset)s and will default to %(core)s.

    The core exchange rate is the price at which %(asset)s are converted to %(core)s.", "title": "手续费资金池", "unclaimed_issuer_income": "发行人未申领收入" }, @@ -1636,6 +1642,7 @@ "account_whitelist": "账户白名单", "all": "显示全部", "assert": "断言操作", + "asset_claim_fee_pool": "Claim fee pool balance", "asset_claim_fees": "领取资产手续费", "asset_claim_pool": "Claim asset fee pool", "asset_create": "创建资产", diff --git a/app/assets/stylesheets/_shame.scss b/app/assets/stylesheets/_shame.scss index 502a517ecd..4c5ab661af 100644 --- a/app/assets/stylesheets/_shame.scss +++ b/app/assets/stylesheets/_shame.scss @@ -57,6 +57,12 @@ hr { padding: 0 !important; } +@include breakpoint(small only) { + .small-no-padding { + padding: 0 !important; + } +} + .no-margin { margin: 0 !important; } diff --git a/app/components/Account/AccountAssetUpdate.jsx b/app/components/Account/AccountAssetUpdate.jsx index 4eb6297d4c..974984493e 100644 --- a/app/components/Account/AccountAssetUpdate.jsx +++ b/app/components/Account/AccountAssetUpdate.jsx @@ -25,7 +25,7 @@ import AssetWhitelist from "./AssetWhitelist"; import AssetFeedProducers from "./AssetFeedProducers"; import BaseModal from "components/Modal/BaseModal"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; -import FundFeePool from "./FundFeePool"; +import FeePoolOperation from "./FeePoolOperation"; import {withRouter} from "react-router-dom"; let GRAPHENE_MAX_SHARE_SUPPLY = new big( @@ -1536,7 +1536,7 @@ class AccountAssetUpdate extends React.Component {
    - value) => value => const keyGetter = key => object => object[key]; -class FundFeePool extends React.Component { +class FeePoolOperation extends React.Component { + static defaultProps = { + type: "fund" + }; + constructor(props) { super(props); this.state = this.initialState(); } + onAccountNameChanged = stateSetter(this, "funderAccountName"); onAccountChanged = stateSetter(this, "newFunderAccount"); onPoolInput = stateSetter(this, "fundPoolAmount", keyGetter("amount")); + + onClaimInput({amount}) { + this.state.claimPoolAsset.setAmount({real: amount}); + this.setState({ + claimPoolAmount: amount + }); + } + onFundPool = () => AssetActions.fundPool( this.state.newFunderAccount @@ -32,14 +45,28 @@ class FundFeePool extends React.Component { this.props.asset, this.state.fundPoolAmount.replace(/,/g, "") ); + reset = () => { this.setState(this.initialState()); }; + initialState = () => ({ funderAccountName: this.props.funderAccountName, - fundPoolAmount: 0 + fundPoolAmount: 0, + fundPoolAsset: new Asset({ + amount: 0, + precision: this.props.core.get("precision"), + asset_id: this.props.core.get("id") + }), + claimPoolAmount: 0, + claimPoolAsset: new Asset({ + amount: 0, + precision: this.props.core.get("precision"), + asset_id: this.props.core.get("id") + }) }); - render = () => { + + renderFundPool() { const { props, state, @@ -57,7 +84,6 @@ class FundFeePool extends React.Component { asset.get("dynamic_asset_data_id") ); const coreID = core.get("id") || "1.3.0"; - const account = newFunderAccount; let balance = 0; if (newFunderAccount) { const coreBalanceID = newFunderAccount.getIn(["balances", coreID]); @@ -76,13 +102,6 @@ class FundFeePool extends React.Component { ); return (
    - - {hideBalance || (
    @@ -140,10 +159,93 @@ class FundFeePool extends React.Component {
    ); - }; + } + + renderClaimPool() { + const {props, onClaim, reset} = this; + const {claimPoolAmount} = this.state; + const {asset, core, getDynamicObject} = props; + let dynamicObject = getDynamicObject( + asset.get("dynamic_asset_data_id") + ); + const coreID = core.get("id") || "1.3.0"; + + const balanceText = !!dynamicObject ? ( + { + this.state.claimPoolAsset.setAmount({ + sats: dynamicObject.get("fee_pool") + }); + this.setState({ + claimPoolAmount: this.state.claimPoolAsset.getAmount({ + real: true + }) + }); + }} + > + :  + + + ) : null; + + return ( +
    + + + +
    + + +
    +
    +

    + :{" "} + +

    +
    +
    +
    + ); + } + + onClaim = () => + AssetActions.claimPool(this.props.asset, this.state.claimPoolAsset); + + render() { + if (this.props.type === "fund") { + return this.renderFundPool(); + } else if (this.props.type === "claim") { + return this.renderClaimPool(); + } + } } -FundFeePool = AssetWrapper(FundFeePool, { +FeePoolOperation = AssetWrapper(FeePoolOperation, { propNames: ["asset", "core"], defaultProps: { core: "1.3.0" @@ -151,4 +253,4 @@ FundFeePool = AssetWrapper(FundFeePool, { withDynamic: true }); -export default FundFeePool; +export default FeePoolOperation; diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index d177ddcf2b..77501a277c 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -16,7 +16,7 @@ import {Apis} from "bitsharesjs-ws"; import {Tabs, Tab} from "../Utility/Tabs"; import {CallOrder, FeedPrice} from "common/MarketClasses"; import Page404 from "../Page404/Page404"; -import FundFeePool from "../Account/FundFeePool"; +import FeePoolOperation from "../Account/FeePoolOperation"; import AccountStore from "stores/AccountStore"; import {connect} from "alt-react"; @@ -226,7 +226,7 @@ class Asset extends React.Component { var marketID = market + "_" + symbol; var marketName = market + "/" + symbol; return ( - + {marketName}{" "}   @@ -534,11 +534,20 @@ class Asset extends React.Component { let dynamic = this.props.getDynamicObject(asset.dynamic_asset_data_id); if (dynamic) dynamic = dynamic.toJS(); var options = asset.options; + const core = ChainStore.getAsset("1.3.0"); + return (
    {}
    +
    - +
    + ); + } + + renderFeePoolFunding(asset) { + return ( +
    +
    +
    + +
    + + +
    +
    + ); + } + + renderFeePoolClaiming(asset) { + let dynamic = this.props.getDynamicObject(asset.dynamic_asset_data_id); + if (dynamic) dynamic = dynamic.toJS(); + return ( +
    +
    +
    + +
    + +
    ); } @@ -774,12 +821,8 @@ class Asset extends React.Component { // he/she owes. If the feed price goes above this, // then getGlobalSettlementPrice() { - var call_orders; if (!this.state.callOrders) { return null; - } else { - // put the call order on the stack - call_orders = this.state.callOrders; } // first get the least collateralized short position @@ -810,7 +853,6 @@ class Asset extends React.Component { // feed_price == collateral / debt let debt = leastColShort.amountToReceive().getAmount(); let collateral = leastColShort.getCollateral().getAmount(); - let globalSettlementPrice = collateral / debt; return (
    -
    +
    {this.renderAboutBox(asset, this.props.asset)}
    -
    -
    +
    +
    {this.renderSummary(asset)}
    -
    - {priceFeed - ? priceFeed - : this.renderPermissions(asset)} +
    + {this.renderPermissions(asset)}
    -
    -
    +
    +
    {this.renderFeePool(asset)}
    -
    - {priceFeed - ? this.renderPermissions(asset) - : null} -
    + {this.renderFeePoolFunding(asset)} + {this.renderFeePoolClaiming(asset)} + + {priceFeed ? ( +
    + {this.renderPriceFeed(asset)} +
    + ) : null}
    {priceFeedData ? priceFeedData : null}
    From d6b54047b94f74d3e2524147757f0d410b45222a Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Mon, 30 Jul 2018 15:29:06 +0200 Subject: [PATCH 35/69] Fix #1596: Add new asset_update_issuer operation, refactor Asset page layout --- app/actions/AssetActions.js | 26 +++ app/assets/locales/locale-de.json | 4 + app/assets/locales/locale-en.json | 4 + app/assets/locales/locale-es.json | 4 + app/assets/locales/locale-fr.json | 4 + app/assets/locales/locale-it.json | 4 + app/assets/locales/locale-ja.json | 4 + app/assets/locales/locale-ko.json | 4 + app/assets/locales/locale-ru.json | 4 + app/assets/locales/locale-tr.json | 4 + app/assets/locales/locale-zh.json | 4 + app/assets/stylesheets/components/_all.scss | 1 + app/assets/stylesheets/components/_asset.scss | 26 +++ .../stylesheets/themes/_theme-template.scss | 3 + app/components/Account/AccountAssetUpdate.jsx | 52 +----- app/components/Account/AccountSelector.jsx | 51 +++--- app/components/Account/FeePoolOperation.jsx | 26 ++- app/components/Blockchain/Asset.jsx | 161 +++++++++++++----- .../Blockchain/AssetOwnerUpdate.jsx | 111 ++++++++++++ app/components/Explorer/AssetOwnerUpdate.jsx | 98 +++++++++++ app/components/Utility/LinkToAccountById.jsx | 14 +- app/components/Utility/TypeAhead.js | 4 + app/lib/common/trxHelper.js | 20 ++- 23 files changed, 497 insertions(+), 136 deletions(-) create mode 100644 app/assets/stylesheets/components/_asset.scss create mode 100644 app/components/Blockchain/AssetOwnerUpdate.jsx create mode 100644 app/components/Explorer/AssetOwnerUpdate.jsx diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index 38b55022e2..e7410b1c16 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -63,6 +63,32 @@ class AssetActions { }; } + updateOwner(asset, new_issuer_id) { + let tr = WalletApi.new_transaction(); + tr.add_type_operation("asset_update_issuer", { + fee: { + amount: 0, + asset_id: "1.3.0" + }, + issuer: asset.issuer, + asset_to_update: asset.id, + new_issuer: new_issuer_id + }); + return dispatch => { + return WalletDb.process_transaction(tr, null, true) + .then(() => { + dispatch(true); + }) + .catch(error => { + console.log( + "[AssetActions.js:150] ----- updateOwner error ----->", + error + ); + dispatch(false); + }); + }; + } + updateFeedProducers(account, asset, producers) { let tr = WalletApi.new_transaction(); tr.add_type_operation("asset_update_feed_producers", { diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index d97581c164..5f53aec54f 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -318,6 +318,8 @@ "Number of feed producers exceeded the max allowed (%(max)s).", "transfer_restricted": "Herauseber muss alle Transfers genehmigen", "update_owner": "Eigentümer aktualisieren", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Hide asset from search and markets", "white_list": "Setze Whitelisting eines Eigentümers voraus", "witness_fed_asset": "Erlaube Witnesses einen Feed bereit zustellen" @@ -622,6 +624,7 @@ "title": "Konten" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Gebühren beanspruchen", @@ -640,6 +643,7 @@ "unclaimed_issuer_income": "Nicht ausgezahlte Herausgeberanteile" }, + "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { "title": "Margin positions" diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index e0a197adba..906c2017d3 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -314,6 +314,8 @@ "Number of feed producers exceeded the max allowed (%(max)s).", "transfer_restricted": "Issuer must approve all transfers", "update_owner": "Update owner", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Hide asset from search and markets", "white_list": "Require holders to be white-listed", "witness_fed_asset": "Allow witnesses to provide feeds" @@ -618,6 +620,7 @@ "title": "Accounts" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Claim fees", @@ -635,6 +638,7 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, + "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { "title": "Margin positions" diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index 7cbad12260..e31958a8db 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -321,6 +321,8 @@ "transfer_restricted": "El emisor debe aprobar todas las transferencias", "update_owner": "Proprietario actualizado", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Ocultar activos desde la búsqueda y el mercados", "white_list": "Requerir que los titulares sean incluidos en la lista blanca", @@ -630,6 +632,7 @@ "title": "Cuentas" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Reclamar tarifas", @@ -647,6 +650,7 @@ "title": "Fondo de Comisiones", "unclaimed_issuer_income": "Ingresos del emisor no reclamados" }, + "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { "title": "posiciòn a margen" diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index ec7c3d5df0..77065a9e91 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -314,6 +314,8 @@ "Number of feed producers exceeded the max allowed (%(max)s).", "transfer_restricted": "Issuer must approve all transfers", "update_owner": "Update owner", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Hide asset from search and markets", "white_list": "Require holders to be white-listed", "witness_fed_asset": "Allow witnesses to provide feeds" @@ -618,6 +620,7 @@ "title": "Comptes" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Claim fees", @@ -635,6 +638,7 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, + "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { "title": "Margin positions" diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index ec982a3cfa..8e7a3eaf89 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -321,6 +321,8 @@ "transfer_restricted": "L'erogatore deve approvare tutti i trasferimenti", "update_owner": "Aggiorna proprietario", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Nascondi asset in ricerca e mercati", "white_list": "Esigi che i possessori siano in white-list", "witness_fed_asset": "Permetti alle witness di fornire feed" @@ -628,6 +630,7 @@ "title": "Account" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Riscuoti commissioni", @@ -645,6 +648,7 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Reddito dell'erogatore non riscosso" }, + "info": "Asset info", "invalid": "Il nome di asset %(name)s non è valido", "margin_positions": { "title": "Posizioni con margine" diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index 3ce5717fe7..32af08f04d 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -312,6 +312,8 @@ "Number of feed producers exceeded the max allowed (%(max)s).", "transfer_restricted": "発行者はすべての転送を承認する必要がある", "update_owner": "オーナーを更新", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "検索と市場からアセットを非表示にする", "white_list": "保有者はホワイトリストに登録されている必要がある", "witness_fed_asset": "証人にフィード供給を許可する" @@ -618,6 +620,7 @@ "title": "アカウント" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "手数料を請求", @@ -635,6 +638,7 @@ "title": "手数料プール", "unclaimed_issuer_income": "未請求の発行者収入" }, + "info": "Asset info", "invalid": "アセット名%(name)sは無効です", "margin_positions": { "title": "マージンポジション" diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index ff7a0313f6..a8446429fe 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -314,6 +314,8 @@ "Number of feed producers exceeded the max allowed (%(max)s).", "transfer_restricted": "Issuer must approve all transfers", "update_owner": "Update owner", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Hide asset from search and markets", "white_list": "Require holders to be white-listed", "witness_fed_asset": "Allow witnesses to provide feeds" @@ -618,6 +620,7 @@ "title": "계정" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Claim fees", @@ -635,6 +638,7 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, + "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { "title": "Margin positions" diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index aa967936b0..2ae604b16f 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -324,6 +324,8 @@ "Число производителей котировок превысило максимально допустимое (%(max)s).", "transfer_restricted": "Эмитент должен одобрять все переводы", "update_owner": "Обновить владельца", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Не отображать актив в поиске и в рынках", "white_list": "Требуется, чтобы держатели находились в белом списке", @@ -632,6 +634,7 @@ "title": "Аккаунты" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Потребовать комиссию", @@ -649,6 +652,7 @@ "title": "Пул комиссии", "unclaimed_issuer_income": "Невостребованный доход эмитента\n" }, + "info": "Asset info", "invalid": "Недопустимое имя %(name)s актива", "margin_positions": { "title": "Маржинальные позиции" diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index 57d69805cf..c0b34644ec 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -316,6 +316,8 @@ "transfer_restricted": "İhrac eden tüm transferleri onlaylamak zorunda", "update_owner": "Sahibi güncelle", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "Hide asset from search and markets", "white_list": "İzin listesi gerektiren dijital varlık", "witness_fed_asset": @@ -624,6 +626,7 @@ "title": "Hesaplar" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "Ücretleri talep et", @@ -641,6 +644,7 @@ "title": "Ücret Havuzu", "unclaimed_issuer_income": "Talep edilmemiş ihraççı geliri" }, + "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { "title": "Margin positions" diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index cf8d27bbe8..0821bf4513 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -302,6 +302,8 @@ "Number of feed producers exceeded the max allowed (%(max)s).", "transfer_restricted": "所有转账必须通过发行人审核同意", "update_owner": "更新发行人", + "update_owner_text": + "The asset owner may change the owner to another account using this form:", "visible": "在搜索与市场中隐藏资产", "white_list": "要求资产持有人预先加入白名单", "witness_fed_asset": "允许见证人提供喂价" @@ -601,6 +603,7 @@ "title": "账户" }, "asset": { + "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", "claim_fees": "领取手续费", @@ -617,6 +620,7 @@ "title": "手续费资金池", "unclaimed_issuer_income": "发行人未申领收入" }, + "info": "Asset info", "invalid": "资产名 %(name)s 无效", "margin_positions": { "title": "债仓" diff --git a/app/assets/stylesheets/components/_all.scss b/app/assets/stylesheets/components/_all.scss index 5ea72702b1..cc1c6a6fd1 100644 --- a/app/assets/stylesheets/components/_all.scss +++ b/app/assets/stylesheets/components/_all.scss @@ -22,6 +22,7 @@ @import "page404"; @import "wallet"; @import "incognito"; +@import "asset"; .lifetime { background: url("../fresh-bolt2.png") no-repeat 100% 50%; diff --git a/app/assets/stylesheets/components/_asset.scss b/app/assets/stylesheets/components/_asset.scss new file mode 100644 index 0000000000..3e86d58780 --- /dev/null +++ b/app/assets/stylesheets/components/_asset.scss @@ -0,0 +1,26 @@ +div.asset-page { + @include breakpoint(medium) { + .grid-block.medium-up-1 { + > div:nth-child(odd) { + padding-left: 0; + } + } + } + + @include breakpoint(medium only) { + .grid-block.medium-up-1 { + > div { + padding-left: 0; + padding-right: 0; + } + } + } + + @include breakpoint(large) { + .grid-block.medium-up-1 { + > div:nth-child(even) { + padding-right: 0; + } + } + } +} diff --git a/app/assets/stylesheets/themes/_theme-template.scss b/app/assets/stylesheets/themes/_theme-template.scss index 8b35b508f1..b3ec9db02f 100644 --- a/app/assets/stylesheets/themes/_theme-template.scss +++ b/app/assets/stylesheets/themes/_theme-template.scss @@ -981,6 +981,9 @@ } } } + &.tab-no-background { + background-color: inherit; + } } // Exchange diff --git a/app/components/Account/AccountAssetUpdate.jsx b/app/components/Account/AccountAssetUpdate.jsx index 974984493e..2ab7395cdb 100644 --- a/app/components/Account/AccountAssetUpdate.jsx +++ b/app/components/Account/AccountAssetUpdate.jsx @@ -13,7 +13,6 @@ import BindToChainState from "../Utility/BindToChainState"; import AssetWrapper from "../Utility/AssetWrapper"; import AmountSelector from "../Utility/AmountSelector"; import FormattedPrice from "../Utility/FormattedPrice"; -import AccountSelector from "../Account/AccountSelector"; import AssetSelector from "../Utility/AssetSelector"; import big from "bignumber.js"; import cnames from "classnames"; @@ -117,7 +116,6 @@ class AccountAssetUpdate extends React.Component { core_exchange_rate: core_exchange_rate, issuer: asset.issuer, new_issuer_account_id: null, - issuer_account_name: null, new_funder_account: props.account.get("id"), asset_to_update: asset.id, errors: { @@ -733,7 +731,7 @@ class AccountAssetUpdate extends React.Component { } render() { - let {account, asset, core} = this.props; + let {asset} = this.props; let { errors, isValid, @@ -1348,51 +1346,9 @@ class AccountAssetUpdate extends React.Component { ) : null} - -
    -
    - -
    - - { -

    - :{" "} - {updateFee} -

    - } -
    -
    -
    { + if (this.props.excludeAccounts.indexOf(accountName) !== -1) + return null; + let account = ChainStore.getAccount(accountName); + let account_status = ChainStore.getAccountMemberStatus( + account + ); + let account_status_text = !accountUtils.isKnownScammer( + accountName + ) + ? "account.member." + account_status + : "account.member.suspected_scammer"; + + typeAheadAccounts.push({ + id: accountName, + label: accountName, + status: counterpart.translate(account_status_text), + className: accountUtils.isKnownScammer(accountName) + ? "negative" + : "positive" + }); + }) + .filter(a => !!a); } let typeaheadHasAccount = !!accountName diff --git a/app/components/Account/FeePoolOperation.jsx b/app/components/Account/FeePoolOperation.jsx index 705c3baa9a..4dd8d3da2f 100644 --- a/app/components/Account/FeePoolOperation.jsx +++ b/app/components/Account/FeePoolOperation.jsx @@ -137,7 +137,7 @@ class FeePoolOperation extends React.Component { style={{width: "100%", paddingTop: 16}} /> -
    +
    -
    -
    -

    - :{" "} - -

    -
    +

    + :{" "} + +

    ); } @@ -209,7 +206,7 @@ class FeePoolOperation extends React.Component { style={{width: "100%", paddingTop: 16}} /> -
    +
    -
    -
    -

    - :{" "} - -

    -
    +

    + :{" "} + +

    ); } diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index 77501a277c..89cf343ef5 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -13,12 +13,13 @@ import utils from "common/utils"; import FormattedTime from "../Utility/FormattedTime"; import {ChainStore} from "bitsharesjs"; import {Apis} from "bitsharesjs-ws"; -import {Tabs, Tab} from "../Utility/Tabs"; import {CallOrder, FeedPrice} from "common/MarketClasses"; import Page404 from "../Page404/Page404"; import FeePoolOperation from "../Account/FeePoolOperation"; import AccountStore from "stores/AccountStore"; import {connect} from "alt-react"; +import AssetOwnerUpdate from "./AssetOwnerUpdate"; +import {Tab, Tabs} from "../Utility/Tabs"; class AssetFlag extends React.Component { render() { @@ -601,6 +602,31 @@ class Asset extends React.Component { ); } + renderAssetOwnerUpdate(asset) { + return ( +
    +
    +
    + +
    + + +
    +
    + ); + } + renderFeePoolFunding(asset) { return (
    @@ -909,7 +935,7 @@ class Asset extends React.Component { {" "} {" "} - +
    ({this.formattedPrice( @@ -918,7 +944,10 @@ class Asset extends React.Component { true )}) - +
    ({this.formattedPrice( @@ -927,15 +956,18 @@ class Asset extends React.Component { true )}) - + {" "} {" "} - + {" "} {" "} - + {" "} {" "} @@ -961,7 +993,10 @@ class Asset extends React.Component { {this.formattedPrice(settlement_price, true)} - + {" "} {this.formattedPrice(core_exchange_rate, true)}{" "} @@ -973,7 +1008,10 @@ class Asset extends React.Component { {" "} {maximum_short_squeeze_ratio} - + @@ -992,7 +1030,7 @@ class Asset extends React.Component { @@ -1013,7 +1051,7 @@ class Asset extends React.Component { ) : null} @@ -1033,7 +1071,10 @@ class Asset extends React.Component { ) : null} - + @@ -1083,21 +1124,30 @@ class Asset extends React.Component { - + - + - + -
    - - {header} - {rows} -
    -
    + + {header} + {rows} +
    @@ -1170,7 +1218,7 @@ class Asset extends React.Component { : null; return ( -
    +
    {this.renderAboutBox(asset, this.props.asset)}
    -
    -
    - {this.renderSummary(asset)} -
    -
    - {this.renderPermissions(asset)} -
    -
    -
    -
    - {this.renderFeePool(asset)} -
    - {this.renderFeePoolFunding(asset)} - {this.renderFeePoolClaiming(asset)} - - {priceFeed ? ( -
    - {this.renderPriceFeed(asset)} + + + +
    +
    + {this.renderSummary(asset)} +
    + +
    + {this.renderPermissions(asset)} +
    + +
    + {this.renderFeePool(asset)} +
    + + {priceFeed ? ( +
    + {this.renderPriceFeed(asset)} +
    + ) : null}
    - ) : null} -
    - {priceFeedData ? priceFeedData : null} + {priceFeedData ? priceFeedData : null} + + +
    + {this.renderAssetOwnerUpdate(asset)} + {this.renderFeePoolFunding(asset)} + {this.renderFeePoolClaiming(asset)} +
    +
    +
    @@ -1213,7 +1283,6 @@ Asset = connect(Asset, { return [AccountStore]; }, getProps() { - const chainID = Apis.instance().chain_id; return { currentAccount: AccountStore.getState().currentAccount || diff --git a/app/components/Blockchain/AssetOwnerUpdate.jsx b/app/components/Blockchain/AssetOwnerUpdate.jsx new file mode 100644 index 0000000000..7c982f99ab --- /dev/null +++ b/app/components/Blockchain/AssetOwnerUpdate.jsx @@ -0,0 +1,111 @@ +import React from "react"; +import AccountSelector from "../Account/AccountSelector"; +import Translate from "react-translate-component"; +import ChainTypes from "../Utility/ChainTypes"; +import BindToChainState from "../Utility/BindToChainState"; +import FormattedFee from "../Utility/FormattedFee"; +import classnames from "classnames"; +import AssetActions from "actions/AssetActions"; + +class AssetOwnerUpdate extends React.Component { + static propTypes = { + account: ChainTypes.ChainAccount.isRequired, + currentOwner: ChainTypes.ChainAccount.isRequired + }; + + constructor() { + super(); + + this.state = { + new_issuer_account_id: null, + issuer_account_name: null + }; + } + + onAccountNameChanged(key, name) { + this.setState({ + [key]: name + }); + } + + onAccountChanged(key, account) { + this.setState({ + [key]: account ? account.get("id") : null + }); + } + + onSubmit() { + AssetActions.updateOwner( + this.props.asset, + this.state.new_issuer_account_id + ).then(() => { + this.onReset(); + }); + } + + onReset() { + this.setState({ + new_issuer_account_id: null, + issuer_account_name: null + }); + } + + render() { + const {currentOwner} = this.props; + + return ( +
    +
    + +
    + +
    + + +
    +

    + :{" "} + +

    +
    + ); + } +} + +AssetOwnerUpdate = BindToChainState(AssetOwnerUpdate); +export default AssetOwnerUpdate; diff --git a/app/components/Explorer/AssetOwnerUpdate.jsx b/app/components/Explorer/AssetOwnerUpdate.jsx new file mode 100644 index 0000000000..8cb6320b4c --- /dev/null +++ b/app/components/Explorer/AssetOwnerUpdate.jsx @@ -0,0 +1,98 @@ +import React from "react"; +import AccountSelector from "../Account/AccountSelector"; +import Translate from "react-translate-component"; +import ChainTypes from "../Utility/ChainTypes"; +import BindToChainState from "../Utility/BindToChainState"; +import FormattedFee from "../Utility/FormattedFee"; + +class AssetOwnerUpdate extends React.Component { + static propTypes = { + account: ChainTypes.ChainAccount.isRequired + }; + + constructor() { + super(); + + this.state = { + new_issuer_account_id: null, + issuer_account_name: null + }; + } + + onAccountNameChanged(key, name) { + this.setState({ + [key]: name + }); + } + + onAccountChanged(key, account) { + this.setState({ + [key]: account ? account.get("id") : null + }); + } + + onSubmit() {} + + onReset() {} + + render() { + const {account} = this.props; + + return ( +
    +
    + +
    + +
    + + +
    +
    +

    + :{" "} + +

    +
    +
    +
    + ); + } +} + +AssetOwnerUpdate = BindToChainState(AssetOwnerUpdate); +export default AssetOwnerUpdate; diff --git a/app/components/Utility/LinkToAccountById.jsx b/app/components/Utility/LinkToAccountById.jsx index 2066d4bc68..a2a2c68643 100644 --- a/app/components/Utility/LinkToAccountById.jsx +++ b/app/components/Utility/LinkToAccountById.jsx @@ -28,14 +28,24 @@ class LinkToAccountById extends React.Component { return {this.props.account.get("id")}; } + const maxDisplayAccountNameLength = 20; + return this.props.noLink ? ( - {account_name} + + {account_name.substr(0, maxDisplayAccountNameLength)} + {account_name.length > maxDisplayAccountNameLength + ? "..." + : null} + ) : ( {}} to={`/account/${account_name}/${this.props.subpage}/`} > - {account_name} + {account_name.substr(0, maxDisplayAccountNameLength)} + {account_name.length > maxDisplayAccountNameLength + ? "..." + : null} ); } diff --git a/app/components/Utility/TypeAhead.js b/app/components/Utility/TypeAhead.js index b5e65cdd65..940f76f021 100644 --- a/app/components/Utility/TypeAhead.js +++ b/app/components/Utility/TypeAhead.js @@ -16,6 +16,10 @@ export default class TypeAhead extends React.Component { if (nextProps.value && nextProps.value != this.state.value) { this.setState({value: nextProps.value}); } + if (nextProps.value === undefined) + this.setState({ + value: nextProps.defaultValue + }); } onClick = () => { diff --git a/app/lib/common/trxHelper.js b/app/lib/common/trxHelper.js index d8f6364d51..51a99c0d44 100644 --- a/app/lib/common/trxHelper.js +++ b/app/lib/common/trxHelper.js @@ -212,9 +212,23 @@ function estimateFee(op_type, options, globalObject, data = {}) { return _feeCache[cacheKey]; } let op_code = operations[op_type]; - let currentFees = globalObject - .getIn(["parameters", "current_fees", "parameters", op_code, 1]) - .toJS(); + let currentFees = globalObject.getIn([ + "parameters", + "current_fees", + "parameters", + op_code, + 1 + ]); + /* Default to transfer fees if the op is missing in globalObject */ + if (!currentFees) + currentFees = globalObject.getIn([ + "parameters", + "current_fees", + "parameters", + 0, + 1 + ]); + currentFees = currentFees.toJS(); let fee = 0; if (currentFees.fee) { From 1a68bbfeaa88183e2a03efe6137abfae2f28e9a0 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Mon, 30 Jul 2018 16:14:48 +0200 Subject: [PATCH 36/69] #1596: Move Asset fee claiming to Asset page actions tab --- app/actions/AssetActions.js | 5 +- app/components/Account/AccountAssetUpdate.jsx | 91 ------------- app/components/Account/FeePoolOperation.jsx | 123 ++++++++++++++++-- app/components/Blockchain/Asset.jsx | 24 +++- 4 files changed, 135 insertions(+), 108 deletions(-) diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index e7410b1c16..73e3fd4a3c 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -118,7 +118,6 @@ class AssetActions { claimPoolFees(account_id, asset, amount) { let tr = WalletApi.new_transaction(); - let precision = utils.get_asset_precision(asset.get("precision")); tr.add_type_operation("asset_claim_fees", { fee: { @@ -128,12 +127,12 @@ class AssetActions { issuer: account_id, amount_to_claim: { asset_id: asset.get("id"), - amount: amount * precision + amount: amount.getAmount() } }); return dispatch => { return WalletDb.process_transaction(tr, null, true) - .then(result => { + .then(() => { dispatch(true); }) .catch(error => { diff --git a/app/components/Account/AccountAssetUpdate.jsx b/app/components/Account/AccountAssetUpdate.jsx index 2ab7395cdb..32ac78d99b 100644 --- a/app/components/Account/AccountAssetUpdate.jsx +++ b/app/components/Account/AccountAssetUpdate.jsx @@ -701,14 +701,6 @@ class AccountAssetUpdate extends React.Component { }); } - _onClaimFees() { - AssetActions.claimPoolFees( - this.props.account.get("id"), - this.props.asset, - this.state.claimFeesAmount.replace(/,/g, "") - ); - } - onChangeList(key, action = "add", id) { let current = this.state[key]; if (action === "add" && !current.includes(id)) { @@ -901,24 +893,6 @@ class AccountAssetUpdate extends React.Component { const dynamicObject = this.props.getDynamicObject( asset.get("dynamic_asset_data_id") ); - let unclaimedBalance = dynamicObject - ? dynamicObject.get("accumulated_fees") - : 0; - let validClaim = - claimFeesAmount > 0 && - utils.get_asset_precision(asset.get("precision")) * - claimFeesAmount <= - unclaimedBalance; - - let unclaimedBalanceText = ( - - :  - - - ); let cerValid = false; @@ -1490,71 +1464,6 @@ class AccountAssetUpdate extends React.Component {
    - -
    - - - {/* Claim fees, disabled until witness node update gets pushed to openledger*/} - - - -
    - :  - {dynamicObject ? ( - - ) : null} -
    - - - -
    - - -
    -
    -
    - {isBitAsset ? ( + AssetActions.claimPool( + this.props.asset, + this.state.claimPoolAmountAsset + ); + renderFundPool() { const { props, @@ -159,7 +181,7 @@ class FeePoolOperation extends React.Component { } renderClaimPool() { - const {props, onClaim, reset} = this; + const {props, onClaimPool, reset} = this; const {claimPoolAmount} = this.state; const {asset, core, getDynamicObject} = props; let dynamicObject = getDynamicObject( @@ -170,13 +192,15 @@ class FeePoolOperation extends React.Component { const balanceText = !!dynamicObject ? ( { - this.state.claimPoolAsset.setAmount({ + this.state.claimPoolAmountAsset.setAmount({ sats: dynamicObject.get("fee_pool") }); this.setState({ - claimPoolAmount: this.state.claimPoolAsset.getAmount({ - real: true - }) + claimPoolAmount: this.state.claimPoolAmountAsset.getAmount( + { + real: true + } + ) }); }} > @@ -198,7 +222,7 @@ class FeePoolOperation extends React.Component { label="transfer.amount" display_balance={balanceText} amount={claimPoolAmount} - onChange={this.onClaimInput.bind(this)} + onChange={this.onClaimInput.bind(this, "claimPoolAmount")} asset={coreID} assets={[coreID]} placeholder="0.0" @@ -211,7 +235,7 @@ class FeePoolOperation extends React.Component { className={classnames("button", { disabled: claimPoolAmount <= 0 })} - onClick={onClaim} + onClick={onClaimPool} > @@ -227,14 +251,87 @@ class FeePoolOperation extends React.Component { ); } - onClaim = () => - AssetActions.claimPool(this.props.asset, this.state.claimPoolAsset); + renderClaimFees() { + const {props} = this; + const {claimFeesAmount} = this.state; + const {asset, getDynamicObject} = props; + let dynamicObject = getDynamicObject( + asset.get("dynamic_asset_data_id") + ); + + let unclaimedBalance = dynamicObject + ? dynamicObject.get("accumulated_fees") + : 0; + let validClaim = + claimFeesAmount > 0 && + this.state.claimFeesAmountAsset.getAmount() <= unclaimedBalance; + + let unclaimedBalanceText = ( + + :  + + + ); + + return ( +
    + +
    + :  + {dynamicObject ? ( + + ) : null} +
    + + + +
    + + +
    +
    + ); + } render() { if (this.props.type === "fund") { return this.renderFundPool(); } else if (this.props.type === "claim") { return this.renderClaimPool(); + } else if (this.props.type === "claim_fees") { + return this.renderClaimFees(); } } } diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index 89cf343ef5..628eb4fa7b 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -670,6 +670,27 @@ class Asset extends React.Component { ); } + renderFeesClaiming(asset) { + let dynamic = this.props.getDynamicObject(asset.dynamic_asset_data_id); + if (dynamic) dynamic = dynamic.toJS(); + return ( +
    +
    +
    + +
    + +
    +
    + ); + } + // TODO: Blacklist Authorities: // TODO: Blacklist Market: Base/Market, Base/Market renderPermissions(asset) { @@ -1265,9 +1286,10 @@ class Asset extends React.Component { className="grid-block vertical large-horizontal medium-up-1 large-up-2" style={{paddingTop: "1rem"}} > - {this.renderAssetOwnerUpdate(asset)} {this.renderFeePoolFunding(asset)} {this.renderFeePoolClaiming(asset)} + {this.renderFeesClaiming(asset)} + {this.renderAssetOwnerUpdate(asset)}
    From c310275ae7dcd09b0fa0bc673229d75483cd982e Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Mon, 30 Jul 2018 17:21:44 +0200 Subject: [PATCH 37/69] #1629: Move burn asset to portfolio, fee claiming to Asset page, clean up assets table --- app/actions/AssetActions.js | 26 ++-- app/assets/icons/fire.svg | 4 + app/assets/icons/icons-loader.js | 3 +- app/components/Account/AccountAssetUpdate.jsx | 36 ++---- app/components/Account/AccountAssets.jsx | 115 ++++++++---------- app/components/Account/AccountOverview.jsx | 3 + .../Account/AccountPortfolioList.jsx | 40 ++++++ app/components/Icon/icon.scss | 4 + app/components/Modal/ReserveAssetModal.jsx | 82 ++++++++++--- app/components/Utility/FormattedAsset.jsx | 2 +- 10 files changed, 198 insertions(+), 117 deletions(-) create mode 100644 app/assets/icons/fire.svg diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index 73e3fd4a3c..2044997711 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -515,17 +515,21 @@ class AssetActions { payer, extensions: [] }); - return WalletDb.process_transaction(tr, null, true) - .then(result => { - return true; - }) - .catch(error => { - console.log( - "[AssetActions.js:150] ----- reserveAsset error ----->", - error - ); - return false; - }); + return dispatch => { + return WalletDb.process_transaction(tr, null, true) + .then(() => { + dispatch(true); + return true; + }) + .catch(error => { + dispatch(false); + console.log( + "[AssetActions.js:150] ----- reserveAsset error ----->", + error + ); + return false; + }); + }; } } diff --git a/app/assets/icons/fire.svg b/app/assets/icons/fire.svg new file mode 100644 index 0000000000..33bc81ef02 --- /dev/null +++ b/app/assets/icons/fire.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/icons/icons-loader.js b/app/assets/icons/icons-loader.js index f5b7f144e3..8ed3d6a2ea 100644 --- a/app/assets/icons/icons-loader.js +++ b/app/assets/icons/icons-loader.js @@ -51,7 +51,8 @@ let icons = [ "filter", "info-circle-o", "zoom", - "people" + "people", + "fire" ]; let iconsMap = {}; diff --git a/app/components/Account/AccountAssetUpdate.jsx b/app/components/Account/AccountAssetUpdate.jsx index 32ac78d99b..7059c19f20 100644 --- a/app/components/Account/AccountAssetUpdate.jsx +++ b/app/components/Account/AccountAssetUpdate.jsx @@ -5,7 +5,6 @@ import AssetActions from "actions/AssetActions"; import HelpContent from "../Utility/HelpContent"; import utils from "common/utils"; import {ChainStore} from "bitsharesjs"; -import FormattedAsset from "../Utility/FormattedAsset"; import FormattedFee from "../Utility/FormattedFee"; import counterpart from "counterpart"; import ChainTypes from "../Utility/ChainTypes"; @@ -24,7 +23,6 @@ import AssetWhitelist from "./AssetWhitelist"; import AssetFeedProducers from "./AssetFeedProducers"; import BaseModal from "components/Modal/BaseModal"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; -import FeePoolOperation from "./FeePoolOperation"; import {withRouter} from "react-router-dom"; let GRAPHENE_MAX_SHARE_SUPPLY = new big( @@ -206,6 +204,7 @@ class AccountAssetUpdate extends React.Component { let tabUpdateIndex = []; + /* Primary */ if ( s.update.max_supply !== p.update.max_supply || s.core_exchange_rate.base.amount !== @@ -215,6 +214,7 @@ class AccountAssetUpdate extends React.Component { ) tabUpdateIndex["0"] = true; + /* Whitelist */ if ( JSON.stringify(s.whitelist_authorities) !== JSON.stringify(p.whitelist_authorities) || @@ -227,6 +227,7 @@ class AccountAssetUpdate extends React.Component { ) tabUpdateIndex["1"] = true; + /* Description */ if ( s.update.description.main !== p.update.description.main || s.update.description.short_name !== @@ -235,38 +236,33 @@ class AccountAssetUpdate extends React.Component { ) tabUpdateIndex["2"] = true; + /* Bitasset options */ if ( JSON.stringify(s.bitasset_opts) !== JSON.stringify(p.original_bitasset_opts) ) tabUpdateIndex["3"] = true; - if ( - s.new_issuer_account_id !== null && - s.new_issuer_account_id !== s.issuer - ) - tabUpdateIndex["4"] = true; - + /* Permissions */ if ( JSON.stringify(s.permissionBooleans) !== JSON.stringify(p.permissionBooleans) ) - tabUpdateIndex["5"] = true; + tabUpdateIndex["4"] = true; + /* Flags */ if ( JSON.stringify(s.flagBooleans) !== JSON.stringify(p.flagBooleans) || s.update.market_fee_percent !== p.update.market_fee_percent || s.update.max_market_fee !== p.update.max_market_fee ) - tabUpdateIndex["6"] = true; - - // Tab 7 == Fee Pool + tabUpdateIndex["5"] = true; if ( JSON.stringify(s.feedProducers) !== JSON.stringify(p.originalFeedProducers) ) - tabUpdateIndex["8"] = true; + tabUpdateIndex["6"] = true; return tabUpdateIndex; } @@ -890,10 +886,6 @@ class AccountAssetUpdate extends React.Component {
    ); - const dynamicObject = this.props.getDynamicObject( - asset.get("dynamic_asset_data_id") - ); - let cerValid = false; if ( @@ -1571,24 +1563,20 @@ class ConfirmModal extends React.Component { ) : null} + {tabsChanged["4"] ? ( -
  • - -
  • - ) : null} - {tabsChanged["5"] ? (
  • ) : null} - {tabsChanged["6"] ? ( + {tabsChanged["5"] ? (
  • ) : null} {/* NEEDS CHECKING */} - {tabsChanged["8"] ? ( + {tabsChanged["6"] ? (
  • diff --git a/app/components/Account/AccountAssets.jsx b/app/components/Account/AccountAssets.jsx index 15d4fc79f9..dfa3be72c7 100644 --- a/app/components/Account/AccountAssets.jsx +++ b/app/components/Account/AccountAssets.jsx @@ -8,17 +8,15 @@ import AccountActions from "actions/AccountActions"; import BaseModal from "../Modal/BaseModal"; import FormattedAsset from "../Utility/FormattedAsset"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; -import notify from "actions/NotificationActions"; -import utils from "common/utils"; import {debounce} from "lodash-es"; import LoadingIndicator from "../LoadingIndicator"; import IssueModal from "../Modal/IssueModal"; -import ReserveAssetModal from "../Modal/ReserveAssetModal"; import {connect} from "alt-react"; import assetUtils from "common/asset_utils"; import {Map, List} from "immutable"; import AssetWrapper from "../Utility/AssetWrapper"; import {Tabs, Tab} from "../Utility/Tabs"; +import Icon from "../Icon/Icon"; class AccountAssets extends React.Component { static defaultProps = { @@ -115,12 +113,6 @@ class AccountAssets extends React.Component { AccountActions.accountSearch(searchTerm); } - _reserveButtonClick(assetId, e) { - e.preventDefault(); - this.setState({reserve: assetId}); - ZfApi.publish("reserve_asset", "open"); - } - _issueButtonClick(asset_id, symbol, e) { e.preventDefault(); let {issue} = this.state; @@ -137,6 +129,10 @@ class AccountAssets extends React.Component { ); } + _createButtonClick(account_name) { + this.props.history.push(`/account/${account_name}/create-asset`); + } + render() { let {account, account_name, assets, assetsList} = this.props; @@ -194,15 +190,26 @@ class AccountAssets extends React.Component { return ( - + {asset.symbol} - {desc} - + + {"bitasset" in asset ? ( + asset.bitasset.is_prediction_market ? ( + + ) : ( + + ) + ) : ( + "User Issued Asset" + )} + + {dynamicObject ? ( ) : null} - + {!asset.bitasset_data_id ? ( - - ) : null} - - - - {!asset.bitasset_data_id ? ( - + + ) : null} - + +
    ); @@ -276,29 +271,38 @@ class AccountAssets extends React.Component { >
    - +
    - - - + @@ -307,13 +311,15 @@ class AccountAssets extends React.Component {
    - - - + +
    @@ -330,19 +336,6 @@ class AccountAssets extends React.Component { /> - - -
    -
    - { - ZfApi.publish("reserve_asset", "close"); - }} - /> -
    -
    ); diff --git a/app/components/Account/AccountOverview.jsx b/app/components/Account/AccountOverview.jsx index f53c7bcf26..0a1ff1b13b 100644 --- a/app/components/Account/AccountOverview.jsx +++ b/app/components/Account/AccountOverview.jsx @@ -529,6 +529,9 @@ class AccountOverview extends React.Component { + + ); } diff --git a/app/components/Icon/icon.scss b/app/components/Icon/icon.scss index 67c0945b4d..9fc9aec6f5 100644 --- a/app/components/Icon/icon.scss +++ b/app/components/Icon/icon.scss @@ -63,6 +63,10 @@ span.icon-10x { fill: black; } +.icon.rotate45 > svg { + transform: rotate(45deg); +} + .icon.rotate90 > svg { transform: rotate(90deg); } diff --git a/app/components/Modal/ReserveAssetModal.jsx b/app/components/Modal/ReserveAssetModal.jsx index a1fcf5c565..67843c94e5 100644 --- a/app/components/Modal/ReserveAssetModal.jsx +++ b/app/components/Modal/ReserveAssetModal.jsx @@ -1,39 +1,64 @@ import React from "react"; import Translate from "react-translate-component"; -import utils from "common/utils"; import BalanceComponent from "../Utility/BalanceComponent"; import counterpart from "counterpart"; import AmountSelector from "../Utility/AmountSelector"; import AssetActions from "actions/AssetActions"; +import {ChainStore} from "bitsharesjs"; +import {Asset} from "common/MarketClasses"; +import AssetWrapper from "../Utility/AssetWrapper"; -export default class ReserveAssetModal extends React.Component { +class ReserveAssetModal extends React.Component { constructor(props) { super(props); - this.state = { - amount: 0 + this.state = this.getInitialState(props); + } + + componentWillReceiveProps(np) { + if ( + np.asset && + this.props.asset && + np.asset.get("id") !== this.props.asset.get("id") + ) { + console.log("new asset:", np.asset.get("id")); + this.setState(this.getInitialState(np)); + } + } + + getInitialState(props) { + return { + amount: 0, + amountAsset: new Asset({ + amount: 0, + asset_id: props.asset.get("id"), + precision: props.asset.get("precision") + }) }; } onAmountChanged({amount, asset}) { + this.state.amountAsset.setAmount({real: amount}); this.setState({amount, asset}); } onSubmit() { - let precision = utils.get_asset_precision( - this.state.asset.get("precision") - ); - let amount = this.state.amount.replace(/,/g, ""); - amount *= precision; AssetActions.reserveAsset( - amount, - this.props.assetId, + this.state.amountAsset.getAmount(), + this.props.asset.get("id"), this.props.account.get("id") - ); + ).then(() => { + this.state.amountAsset.setAmount({sats: 0}); + this.setState({amount: 0}); + }); this.props.onClose(); } render() { - let assetId = this.props.assetId; + let assetId = this.props.asset.get("id"); + + let currentBalance = ChainStore.getObject( + this.props.account.getIn(["balances", assetId]) + ); return ( @@ -47,12 +72,25 @@ export default class ReserveAssetModal extends React.Component { asset={assetId} assets={[assetId]} display_balance={ - +
    { + this.state.amountAsset.setAmount({ + sats: currentBalance.get("balance") + }); + this.setState({ + amount: this.state.amountAsset.getAmount( + {real: true} + ) + }); + }} + > + +
    } tabIndex={1} /> @@ -82,3 +120,9 @@ export default class ReserveAssetModal extends React.Component { ); } } + +ReserveAssetModal = AssetWrapper(ReserveAssetModal, { + propNames: ["asset"] +}); + +export default ReserveAssetModal; diff --git a/app/components/Utility/FormattedAsset.jsx b/app/components/Utility/FormattedAsset.jsx index 72a8241594..46dd7cc8cc 100755 --- a/app/components/Utility/FormattedAsset.jsx +++ b/app/components/Utility/FormattedAsset.jsx @@ -172,7 +172,7 @@ class FormattedAsset extends React.Component { ) : ( - {" "} +   Date: Mon, 30 Jul 2018 17:30:37 +0200 Subject: [PATCH 38/69] Remove fee estimates from Asset actions page --- app/components/Account/FeePoolOperation.jsx | 11 +-- .../Blockchain/AssetOwnerUpdate.jsx | 5 - app/components/Explorer/AssetOwnerUpdate.jsx | 98 ------------------- 3 files changed, 1 insertion(+), 113 deletions(-) delete mode 100644 app/components/Explorer/AssetOwnerUpdate.jsx diff --git a/app/components/Account/FeePoolOperation.jsx b/app/components/Account/FeePoolOperation.jsx index 6d8ed4eb1e..f7cdc84b29 100644 --- a/app/components/Account/FeePoolOperation.jsx +++ b/app/components/Account/FeePoolOperation.jsx @@ -5,7 +5,6 @@ import {Asset} from "common/MarketClasses"; import AccountSelector from "../Account/AccountSelector"; import AmountSelector from "../Utility/AmountSelector"; import FormattedAsset from "../Utility/FormattedAsset"; -import FormattedFee from "../Utility/FormattedFee"; import AssetActions from "actions/AssetActions"; import AssetWrapper from "../Utility/AssetWrapper"; import {ChainStore} from "bitsharesjs"; @@ -172,10 +171,6 @@ class FeePoolOperation extends React.Component { -

    - :{" "} - -

    ); } @@ -243,10 +238,6 @@ class FeePoolOperation extends React.Component { -

    - :{" "} - -

    ); } @@ -305,7 +296,7 @@ class FeePoolOperation extends React.Component { style={{width: "100%", paddingTop: 16}} /> -
    +
    -

    - :{" "} - -

    ); } diff --git a/app/components/Explorer/AssetOwnerUpdate.jsx b/app/components/Explorer/AssetOwnerUpdate.jsx deleted file mode 100644 index 8cb6320b4c..0000000000 --- a/app/components/Explorer/AssetOwnerUpdate.jsx +++ /dev/null @@ -1,98 +0,0 @@ -import React from "react"; -import AccountSelector from "../Account/AccountSelector"; -import Translate from "react-translate-component"; -import ChainTypes from "../Utility/ChainTypes"; -import BindToChainState from "../Utility/BindToChainState"; -import FormattedFee from "../Utility/FormattedFee"; - -class AssetOwnerUpdate extends React.Component { - static propTypes = { - account: ChainTypes.ChainAccount.isRequired - }; - - constructor() { - super(); - - this.state = { - new_issuer_account_id: null, - issuer_account_name: null - }; - } - - onAccountNameChanged(key, name) { - this.setState({ - [key]: name - }); - } - - onAccountChanged(key, account) { - this.setState({ - [key]: account ? account.get("id") : null - }); - } - - onSubmit() {} - - onReset() {} - - render() { - const {account} = this.props; - - return ( -
    -
    - -
    - -
    - - -
    -
    -

    - :{" "} - -

    -
    -
    -
    - ); - } -} - -AssetOwnerUpdate = BindToChainState(AssetOwnerUpdate); -export default AssetOwnerUpdate; From 56a5f4b74e592dddf78d933311085b78bebd7e5d Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Mon, 30 Jul 2018 21:16:51 +0200 Subject: [PATCH 39/69] #1131: Add feed price publishing to Asset page --- app/actions/AssetActions.js | 28 +++ app/assets/locales/locale-en.json | 3 + app/components/Blockchain/Asset.jsx | 30 ++- .../Blockchain/AssetPublishFeed.jsx | 188 ++++++++++++++++++ app/components/Utility/AmountSelector.jsx | 25 ++- app/components/Utility/PriceInput.jsx | 72 +++++++ app/lib/common/MarketClasses.js | 36 ++-- 7 files changed, 358 insertions(+), 24 deletions(-) create mode 100644 app/components/Blockchain/AssetPublishFeed.jsx create mode 100644 app/components/Utility/PriceInput.jsx diff --git a/app/actions/AssetActions.js b/app/actions/AssetActions.js index 2044997711..59b6532201 100644 --- a/app/actions/AssetActions.js +++ b/app/actions/AssetActions.js @@ -9,6 +9,34 @@ import {gatewayPrefixes} from "common/gateways"; let inProgress = {}; class AssetActions { + publishFeed({publisher, asset_id, mcr, mssr, settlementPrice, cer}) { + let tr = WalletApi.new_transaction(); + tr.add_type_operation("asset_publish_feed", { + publisher, + asset_id, + feed: { + settlement_price: settlementPrice.toObject(), + maintenance_collateral_ratio: mcr, + maximum_short_squeeze_ratio: mssr, + core_exchange_rate: cer.toObject() + } + }); + + return dispatch => { + return WalletDb.process_transaction(tr, null, true) + .then(() => { + dispatch(true); + }) + .catch(error => { + console.log( + "[AssetActions.js:150] ----- fundPool error ----->", + error + ); + dispatch(false); + }); + }; + } + fundPool(account_id, core, asset, amount) { let tr = WalletApi.new_transaction(); let precision = utils.get_asset_precision(core.get("precision")); diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 906c2017d3..92735eb540 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -620,6 +620,9 @@ "title": "Accounts" }, "asset": { + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index 628eb4fa7b..474cfaadb7 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -19,6 +19,7 @@ import FeePoolOperation from "../Account/FeePoolOperation"; import AccountStore from "stores/AccountStore"; import {connect} from "alt-react"; import AssetOwnerUpdate from "./AssetOwnerUpdate"; +import AssetPublishFeed from "./AssetPublishFeed"; import {Tab, Tabs} from "../Utility/Tabs"; class AssetFlag extends React.Component { @@ -627,6 +628,30 @@ class Asset extends React.Component { ); } + renderFeedPublish(asset) { + return ( +
    +
    +
    + +
    + + +
    +
    + ); + } + renderFeePoolFunding(asset) { return (
    @@ -890,7 +915,6 @@ class Asset extends React.Component { if (leastColShort == null) { // couldn't find the least colshort? - console.log("couldn't find the least col short"); return null; } @@ -1290,6 +1314,10 @@ class Asset extends React.Component { {this.renderFeePoolClaiming(asset)} {this.renderFeesClaiming(asset)} {this.renderAssetOwnerUpdate(asset)} + {"bitasset" in asset && + !asset.bitasset.is_prediction_market + ? this.renderFeedPublish(asset) + : null}
    diff --git a/app/components/Blockchain/AssetPublishFeed.jsx b/app/components/Blockchain/AssetPublishFeed.jsx new file mode 100644 index 0000000000..5da24c6c84 --- /dev/null +++ b/app/components/Blockchain/AssetPublishFeed.jsx @@ -0,0 +1,188 @@ +import React from "react"; +import AccountSelector from "../Account/AccountSelector"; +import Translate from "react-translate-component"; +import ChainTypes from "../Utility/ChainTypes"; +import BindToChainState from "../Utility/BindToChainState"; +import classnames from "classnames"; +import AssetActions from "actions/AssetActions"; +import AssetWrapper from "../Utility/AssetWrapper"; +import PriceInput from "../Utility/PriceInput"; +import AmountSelector from "../Utility/AmountSelector"; + +class AssetPublishFeed extends React.Component { + static propTypes = { + account: ChainTypes.ChainAccount.isRequired + }; + + constructor(props) { + super(); + + this.state = this.resetState(props); + } + + resetState(props = this.props) { + let publisher_id = props.account.get("id"); + + const currentFeed = props.base.getIn(["bitasset", "current_feed"]); + + /* Might need to check these default values */ + let mcr = currentFeed.get("maintenance_collateral_ratio", 1750); + let mssr = currentFeed.get("maximum_short_squeeze_ratio", 1100); + + return { + publisher: props.account.get("name"), + publisher_id, + mcr, + mcrValue: mcr / 10, + mssr, + mssrValue: mssr / 10 + }; + } + + onAccountNameChanged(key, name) { + this.setState({ + [key]: name + }); + } + + onAccountChanged(key, account) { + this.setState({ + [key]: account ? account.get("id") : null + }); + } + + onSubmit() { + AssetActions.publishFeed({ + publisher: this.state.publisher_id, + asset_id: this.props.base.get("id"), + mcr: this.state.mcr, + mssr: this.state.mssr, + settlementPrice: this.state.settlementPrice, + cer: this.state.cer + }); + // .then(() => { + // this.setState(this.resetState()); + // }); + } + + onPriceChanged(key, value) { + this.setState({ + [key]: value + }); + } + + onSetRatio(key, {amount}) { + /* Enforce one decimal point maximum */ + if ( + !!amount && + typeof amount === "string" && + amount.indexOf(".") !== -1 && + amount.indexOf(".") + 2 !== amount.length + ) { + amount = amount.substr(0, amount.indexOf(".") + 2); + } + this.setState({ + [key + "Value"]: amount, + [key]: Math.floor(parseFloat(amount) * 10) + }); + } + + render() { + const {quote, base} = this.props; + const {mcrValue, mssrValue, publisher} = this.state; + + return ( +
    + + + {/* Core Exchange Rate */} +
    + + + {/* Settlement Price */} +
    + + + {/* MCR */} +
    + + + {/* MSSR */} +
    + + +
    + + + {/* */} +
    +
    + ); + } +} + +AssetPublishFeed = BindToChainState(AssetPublishFeed); +AssetPublishFeed = AssetWrapper(AssetPublishFeed, { + propNames: ["quote", "base"], + defaultProps: { + quote: "1.3.0" + } +}); +export default AssetPublishFeed; diff --git a/app/components/Utility/AmountSelector.jsx b/app/components/Utility/AmountSelector.jsx index a54b3cea24..166c0e2b22 100755 --- a/app/components/Utility/AmountSelector.jsx +++ b/app/components/Utility/AmountSelector.jsx @@ -123,14 +123,25 @@ class AmountSelector extends React.Component { onChange={this._onChange.bind(this)} tabIndex={this.props.tabIndex} /> +
    - + {this.props.isPrice ? ( +
    +
    + {this.props.asset.get("symbol")}/{ + this.props.base + } +
    +
    + ) : ( + + )}
    diff --git a/app/components/Utility/PriceInput.jsx b/app/components/Utility/PriceInput.jsx new file mode 100644 index 0000000000..42c5aef43d --- /dev/null +++ b/app/components/Utility/PriceInput.jsx @@ -0,0 +1,72 @@ +import React from "react"; +import AmountSelector from "./AmountSelector"; +import {Price, Asset} from "common/MarketClasses"; +import AssetWrapper from "../Utility/AssetWrapper"; + +class PriceInput extends React.Component { + constructor(props) { + super(); + + let quote = new Asset({ + amount: 0, + asset_id: props.quote.get("id"), + precision: props.quote.get("precision") + }); + let base = new Asset({ + amount: 0, + asset_id: props.base.get("id"), + precision: props.base.get("precision") + }); + + let price = new Price({ + quote, + base + }); + + this.state = { + price, + realPriceValue: price.toReal() + }; + } + + onPriceChanged({amount}) { + this.state.price.setPriceFromReal(parseFloat(amount)); + this.setState({ + realPriceValue: amount + }); + + if (this.props.onPriceChanged) + this.props.onPriceChanged(this.state.price.clone()); + } + + render() { + const {realPriceValue, price} = this.state; + + return ( + + ); + } +} + +PriceInput = AssetWrapper(PriceInput, { + propNames: ["quote", "base"], + defaultProps: { + base: "1.3.0" + } +}); + +export default PriceInput; diff --git a/app/lib/common/MarketClasses.js b/app/lib/common/MarketClasses.js index fad7298a9c..9d50dc406a 100644 --- a/app/lib/common/MarketClasses.js +++ b/app/lib/common/MarketClasses.js @@ -213,8 +213,22 @@ class Price { throw new Error("Base and Quote assets must be different"); } - base = base.clone(); - quote = quote.clone(); + if ( + !base.asset_id || + !("amount" in base) || + !quote.asset_id || + !("amount" in quote) + ) { + throw new Error("Invalid Price inputs"); + } + + this.base = base.clone(); + this.quote = quote.clone(); + + this.setPriceFromReal(real); + } + + setPriceFromReal(real, base = this.base, quote = this.quote) { if (real && typeof real === "number") { /* * In order to make large numbers work properly, we assume numbers @@ -236,22 +250,12 @@ class Price { numRatio = 1; } - base.amount = frac.numerator * numRatio; - quote.amount = frac.denominator * denRatio; + base.setAmount({sats: frac.numerator * numRatio}); + quote.setAmount({sats: frac.denominator * denRatio}); } else if (real === 0) { - base.amount = 0; - quote.amount = 0; + base.setAmount({sats: 0}); + quote.setAmount({sats: 0}); } - - if ( - !base.asset_id || - !("amount" in base) || - !quote.asset_id || - !("amount" in quote) - ) - throw new Error("Invalid Price inputs"); - this.base = base; - this.quote = quote; } getUnits() { From f0f3458717477ceaefa1584015f1f5e19ad5c971 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Tue, 31 Jul 2018 17:25:02 +0200 Subject: [PATCH 40/69] #1131: Use ratio instead of percent for mcr and mssr --- app/components/Blockchain/Asset.jsx | 141 +++++++----------- .../Blockchain/AssetPublishFeed.jsx | 10 +- 2 files changed, 55 insertions(+), 96 deletions(-) diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index 474cfaadb7..75d96e74d9 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -213,7 +213,6 @@ class Asset extends React.Component { return authorities.map(function(authority) { return ( - {" "} ); @@ -229,7 +228,7 @@ class Asset extends React.Component { var marketName = market + "/" + symbol; return ( - {marketName}{" "} + {marketName}   ); @@ -319,15 +318,13 @@ class Asset extends React.Component { var currentSupply = dynamic ? (
    ) : null; @@ -335,15 +332,13 @@ class Asset extends React.Component { var stealthSupply = dynamic ? ( ) : null; @@ -351,8 +346,7 @@ class Asset extends React.Component { var marketFee = flagBooleans["charge_market_fee"] ? ( @@ -362,15 +356,13 @@ class Asset extends React.Component { var maxMarketFee = flagBooleans["charge_market_fee"] ? ( ) : null; @@ -384,27 +376,21 @@ class Asset extends React.Component { @@ -453,51 +439,42 @@ class Asset extends React.Component { @@ -510,19 +487,16 @@ class Asset extends React.Component { @@ -557,44 +531,38 @@ class Asset extends React.Component { @@ -739,15 +707,13 @@ class Asset extends React.Component { var maxMarketFee = permissionBooleans["charge_market_fee"] ? ( ) : null; @@ -756,15 +722,13 @@ class Asset extends React.Component { var maxSupply = ( ); @@ -789,7 +753,7 @@ class Asset extends React.Component { return (
    - {}{" "} + {}
    + - + + + - + + +
    + + { @@ -561,6 +570,23 @@ class AccountPortfolioList extends React.Component { emptyCell )} + + {!isBitAsset ? ( + + + + ) : null} + + + {/* Burn modal */} + +
    +
    + { + ZfApi.publish("reserve_asset", "close"); + }} + /> +
    +
    - {" "} - {" "} + - {" "} {" "} + />
    - {" "} - {" "} + - {" "} {" "} + />
    - {" "} - {" "} + {options.market_fee_percent / 100.0} %
    - {" "} - {" "} + - {" "} {" "} + />
    - {" "} - {" "} + {this._assetType(asset)}
    - {" "} - {" "} + - {" "} - {" "} +
    - {" "} - {" "} + {asset.precision}
    - {" "} - {" "} + - {" "} {this.formattedPrice( currentFeed.settlement_price - )}{" "} + )}
    - {" "} - {" "} + - {" "} {currentFeed.maintenance_collateral_ratio / - 10}%{" "} + 1000}
    - {" "} - {" "} + - {" "} - {currentFeed.maximum_short_squeeze_ratio / - 10}%{" "} + {currentFeed.maximum_short_squeeze_ratio / 1000}
    - {" "} - {" "} + - {" "} {globalSettlementPrice ? globalSettlementPrice - : "-"}{" "} + : "-"}
    - {" "} - {" "} + - {" "} - {" "} +
    - {" "} - {" "} + {settlementOffset / 100}%
    - {" "} - {" "} + - {" "} {this.formattedPrice( options.core_exchange_rate - )}{" "} + )}
    - {" "} - {" "} + - {" "} {dynamic ? ( - ) : null}{" "} + ) : null}
    - {" "} - {" "} + - {" "} {dynamic ? ( - ) : null}{" "} + ) : null}
    - {" "} - {" "} + - {" "} {" "} + />
    - {" "} - {" "} + - {" "} {" "} + />
    @@ -1026,14 +986,13 @@ class Asset extends React.Component { var settlement_price = feed[1][1].settlement_price; var core_exchange_rate = feed[1][1].core_exchange_rate; var maintenance_collateral_ratio = - "" + feed[1][1].maintenance_collateral_ratio / 10 + "%"; + "" + feed[1][1].maintenance_collateral_ratio / 1000; var maximum_short_squeeze_ratio = - "" + feed[1][1].maximum_short_squeeze_ratio / 10 + "%"; + "" + feed[1][1].maximum_short_squeeze_ratio / 1000; rows.push( - - {/* {marketIndex > 0 ? : null} */} - {marketOrders[market].sort((a, b) => { - return a.props.price - b.props.price; - })} - + tables = tables.concat( + marketOrders[market].sort((a, b) => { + return a.props.price - b.props.price; + }) ); - marketIndex++; + // tables.push( + // + // {/* {marketIndex > 0 ? : null} */} + // {marketOrders[market].sort((a, b) => { + // return a.props.price - b.props.price; + // })} + // + // ); + // marketIndex++; } } + // tables.sort((a, b) => { + // return parseInt(a.key, 10) - parseInt(b.key, 10); + // }) + return (
    -
    - {" "} - {" "} + @@ -1002,19 +965,16 @@ class Asset extends React.Component { )}) - {" "} - {" "} + - {" "} - {" "} + - {" "} - {" "} +
    - {" "} - {" "} + {this.formattedPrice(settlement_price, true)} @@ -1042,15 +1001,12 @@ class Asset extends React.Component { style={{textAlign: "right"}} className="column-hide-small" > - {" "} - {this.formattedPrice(core_exchange_rate, true)}{" "} + {this.formattedPrice(core_exchange_rate, true)} - {" "} {maintenance_collateral_ratio} - {" "} {maximum_short_squeeze_ratio} @@ -1090,12 +1047,13 @@ class Asset extends React.Component { .asset_id } hide_amount - />{" "} + /> ) ) : null} @@ -1111,13 +1069,13 @@ class Asset extends React.Component { .asset_id } hide_amount - />{" "} + /> ) ) : null} ) : null} + @@ -1216,7 +1175,7 @@ class Asset extends React.Component { }); return ( -
    +
    Date: Wed, 1 Aug 2018 09:33:28 +0200 Subject: [PATCH 41/69] Close #1576: Add target collateral ratio to orderbook calculations (#1735) * Initial work * Remove console logs * Implement feedback from abit * Add an assert checking the new collateral ratio --- app/lib/common/MarketClasses.js | 205 ++++++++++++++++++++++++++++---- app/test/marketTests.js | 122 +++++++++++++++++-- 2 files changed, 290 insertions(+), 37 deletions(-) diff --git a/app/lib/common/MarketClasses.js b/app/lib/common/MarketClasses.js index 9d50dc406a..b55f9885ce 100644 --- a/app/lib/common/MarketClasses.js +++ b/app/lib/common/MarketClasses.js @@ -616,20 +616,25 @@ class CallOrder { throw new Error("CallOrder missing inputs"); } + this.isSum = false; this.order = order; this.assets = assets; this.market_base = market_base; this.is_prediction_market = is_prediction_market; + /* inverted = price in collateral / debt, !inverted = price in debt / collateral */ this.inverted = market_base === order.call_price.base.asset_id; this.id = order.id; this.borrower = order.borrower; this.borrowers = [order.borrower]; + this.target_collateral_ratio = order.target_collateral_ratio + ? order.target_collateral_ratio / 1000 + : null; /* Collateral asset type is call_price.base.asset_id */ - this.for_sale = parseInt(order.collateral, 10); - this.for_sale_id = order.call_price.base.asset_id; + this.collateral = parseInt(order.collateral, 10); + this.collateral_id = order.call_price.base.asset_id; /* Debt asset type is call_price.quote.asset_id */ - this.to_receive = parseInt(order.debt, 10); - this.to_receive_id = order.call_price.quote.asset_id; + this.debt = parseInt(order.debt, 10); + this.debt_id = order.call_price.quote.asset_id; let base = new Asset({ asset_id: order.call_price.base.asset_id, @@ -642,15 +647,20 @@ class CallOrder { precision: assets[order.call_price.quote.asset_id].precision }); + this.precisionsRatio = + precisionToRatio(assets[this.debt_id].precision) / + precisionToRatio(assets[this.collateral_id].precision); + /* * The call price is DEBT * MCR / COLLATERAL. This calculation is already * done by the witness_node before returning the orders so it is not necessary * to deal with the MCR (maintenance collateral ratio) here. */ this.call_price = new Price({ - base: this.inverted ? quote : base, - quote: this.inverted ? base : quote + base: base, + quote: quote }); + if (this.inverted) this.call_price = this.call_price.invert(); if (feed.base.asset_id !== this.call_price.base.asset_id) { throw new Error( @@ -659,6 +669,11 @@ class CallOrder { } this.feed_price = feed; + + /* BSIP38 implementation */ + this.assignMaxDebtAndCollateral(); + + this.expiration = {toLocaleString: () => null}; } clone(f = this.feed_price) { @@ -725,12 +740,98 @@ class CallOrder { getCollateral() { if (this._collateral) return this._collateral; return (this._collateral = new Asset({ - amount: this.for_sale, - asset_id: this.for_sale_id, - precision: this.assets[this.for_sale_id].precision + amount: this.collateral, + asset_id: this.collateral_id, + precision: this.assets[this.collateral_id].precision })); } + _getMaxCollateralToSell() { + /* + BSIP38: https://github.com/bitshares/bsips/blob/master/bsip-0038.md + * max_amount_to_sell = (debt * target_CR - collateral * feed_price) + * / (target_CR * match_price - feed_price) + */ + if ( + this.target_collateral_ratio && + this.getRatio() < this.target_collateral_ratio + ) { + let feed_price = this._getFeedPrice(); + let match_price = this._getMatchPrice(); + let nominator = + this.debt * this.target_collateral_ratio - + this.collateral * feed_price; + let denominator = + this.target_collateral_ratio * match_price - feed_price; + return nominator / denominator; + } else { + return this.collateral; + } + } + + _getMaxDebtToCover() { + let max_collateral_to_sell = this._getMaxCollateralToSell(); + let match_price = this._getMatchPrice(); + return max_collateral_to_sell * match_price; + } + + /* Returns satoshi feed price in consistent units of debt/collateral */ + _getFeedPrice() { + return ( + (this.inverted + ? this.getFeedPrice() + : this.feed_price.invert().toReal()) * this.precisionsRatio + ); + } + + /* Returns satoshi match price in consistent units of debt/collateral */ + _getMatchPrice() { + return ( + (this.inverted + ? this.getSqueezePrice() + : parseFloat((1 / this.getSqueezePrice()).toFixed(8))) * + this.precisionsRatio + ); + } + + assignMaxDebtAndCollateral() { + if (!this.target_collateral_ratio) return; + let match_price = this._getMatchPrice(); + let max_debt_to_cover = this._getMaxDebtToCover(), + max_debt_to_cover_int; + /* + * We may calculate like this: if max_debt_to_cover has no fractional + * component (e.g. 5.00 as opposed to 5.23), plus it by one Satoshi; + * otherwise, round it up. An effectively same approach is to round + * down then add one Satoshi onto the result: + */ + if (Math.round(max_debt_to_cover) !== max_debt_to_cover) { + max_debt_to_cover_int = Math.floor(max_debt_to_cover) + 1; + } + + /* + * With max_debt_to_cover_int in integer, max_amount_to_sell_int in + * integer can be calculated as: max_amount_to_sell_int = + * round_up(max_debt_to_cover_int / match_price) + */ + let max_collateral_to_sell_int = Math.ceil( + max_debt_to_cover_int / match_price + ); + + /* Assign to Assets */ + this.max_debt_to_cover = new Asset({ + amount: max_debt_to_cover_int, + asset_id: this.debt_id, + precision: this.assets[this.debt_id].precision + }); + + this.max_collateral_to_sell = new Asset({ + amount: max_collateral_to_sell_int, + asset_id: this.collateral_id, + precision: this.assets[this.collateral_id].precision + }); + } + /* * Assume a USD:BTS market * The call order will always be selling BTS in order to buy USD @@ -739,25 +840,37 @@ class CallOrder { * collateral will be sold to cover the debt */ amountForSale(isBid = this.isBid()) { + /* + BSIP38: + * max_amount_to_sell = (debt * target_CR - collateral * feed_price) + * / (target_CR * match_price - feed_price) + */ if (this._for_sale) return this._for_sale; - // return this._for_sale = new Asset({ - // asset_id: this.for_sale_id, - // amount: this.for_sale, - // precision: this.assets[this.for_sale_id].precision - // }); + if (this._useTargetCR() || this.isSum) { + return (this._for_sale = this.max_collateral_to_sell); + } return (this._for_sale = this.amountToReceive().times( this.feed_price.getSqueezePrice(), isBid )); } + _useTargetCR() { + return ( + !!this.target_collateral_ratio && + this.getRatio() < this.target_collateral_ratio + ); + } + amountToReceive() { if (this._to_receive) return this._to_receive; - // return this._to_receive = this.amountForSale().times(this.feed_price.getSqueezePrice(), isBid); + if (this._useTargetCR() || this.isSum) { + return (this._to_receive = this.max_debt_to_cover); + } return (this._to_receive = new Asset({ - asset_id: this.to_receive_id, - amount: this.to_receive, - precision: this.assets[this.to_receive_id].precision + asset_id: this.debt_id, + amount: this.debt, + precision: this.assets[this.debt_id].precision })); } @@ -766,9 +879,49 @@ class CallOrder { if (newOrder.borrowers.indexOf(order.borrower) === -1) { newOrder.borrowers.push(order.borrower); } - newOrder.to_receive += order.to_receive; - newOrder.for_sale += order.for_sale; + + /* Determine which debt values to use */ + let orderDebt = order.iSum + ? order.debt + : order._useTargetCR() + ? order.max_debt_to_cover.getAmount() + : order.amountToReceive().getAmount(); + let newOrderDebt = newOrder.iSum + ? newOrder.debt + : newOrder._useTargetCR() + ? newOrder.max_debt_to_cover.getAmount() + : newOrder.amountToReceive().getAmount(); + newOrder.debt = newOrderDebt + orderDebt; + + /* Determine which collateral values to use */ + let orderCollateral = order.iSum + ? order.collateral + : order._useTargetCR() + ? order.max_collateral_to_sell.getAmount() + : order.amountForSale().getAmount(); + let newOrderCollateral = newOrder.iSum + ? newOrder.collateral + : newOrder._useTargetCR() + ? newOrder.max_collateral_to_sell.getAmount() + : newOrder.amountForSale().getAmount(); + newOrder.collateral = newOrderCollateral + orderCollateral; newOrder._clearCache(); + + /* Assign max collateral to sell and max debt to buy as the summed amounts */ + newOrder.max_debt_to_cover = new Asset({ + amount: newOrder.debt, + asset_id: this.debt_id, + precision: this.assets[this.debt_id].precision + }); + + newOrder.max_collateral_to_sell = new Asset({ + amount: newOrder.collateral, + asset_id: this.collateral_id, + precision: this.assets[this.collateral_id].precision + }); + + newOrder.isSum = true; + return newOrder; } @@ -785,8 +938,8 @@ class CallOrder { return ( this.call_price.ne(order.call_price) || this.feed_price.ne(order.feed_price) || - this.to_receive !== order.to_receive || - this.for_sale !== order.for_sale + this.debt !== order.debt || + this.collateral !== order.collateral ); } @@ -819,15 +972,15 @@ class CallOrder { getRatio() { return ( - this.getCollateral().getAmount({real: true}) / - this.amountToReceive().getAmount({real: true}) / - this.getFeedPrice() + this.collateral / // CORE + (this.debt / // DEBT + this._getFeedPrice()) // DEBT/CORE ); } getStatus() { const mr = - this.assets[this.to_receive_id].bitasset.current_feed + this.assets[this.debt_id].bitasset.current_feed .maintenance_collateral_ratio / 1000; const cr = this.getRatio(); diff --git a/app/test/marketTests.js b/app/test/marketTests.js index 05c5cf918c..db8b90cc18 100644 --- a/app/test/marketTests.js +++ b/app/test/marketTests.js @@ -954,12 +954,12 @@ describe("LimitOrder", function() { describe("CallOrder", function() { let base = { - amount: 31, + amount: 8127, asset_id: "1.3.113" }; let quote = { - amount: 10624, + amount: 59170, asset_id: "1.3.0" }; @@ -1007,7 +1007,7 @@ describe("CallOrder", function() { debt: 498820000, call_price: { base: { - amount: "13558072233", + amount: "1355807223", asset_id: "1.3.0" }, quote: { @@ -1017,11 +1017,29 @@ describe("CallOrder", function() { } }; + const o3_target_cr = { + id: "1.8.2317", + borrower: "1.2.115227", + collateral: "120000", + debt: 10000, + call_price: { + base: { + amount: "1355807223", + asset_id: "1.3.0" + }, + quote: { + amount: 349300000, + asset_id: "1.3.113" + } + }, + target_collateral_ratio: 1750 + }; + it("Instantiates", function() { let order = new CallOrder(o, assets, "1.3.0", settlePrice_0); assert.equal(order.id, o.id, "Id should be 1.8.2317"); - assert.equal(order.for_sale, o.collateral); - assert.equal(order.to_receive, o.debt); + assert.equal(order.collateral, o.collateral); + assert.equal(order.debt, o.debt); }); it("Returns the call price of the order", function() { @@ -1095,13 +1113,13 @@ describe("CallOrder", function() { assert.equal( forSale.getAmount(), - 188045485419, - "Satoshi amount for sale should equal 188045485419" + 3994917846, + "Satoshi amount for sale should equal 3994917846" ); assert.equal( forSale.getAmount({real: true}), - 1880454.85419, - "Real amount for sale should equal 1880454.85419" + 39949.17846, + "Real amount for sale should equal 39949.17846" ); }); @@ -1126,10 +1144,17 @@ describe("CallOrder", function() { let o2 = new CallOrder(o, assets, "1.3.0", settlePrice_0); const o3 = o1.sum(o2); + assert(o3.isSum); + assert.equal( + o3.amountToReceive().getAmount(), + 498820000 * 2, + "The amount should equal 997640000" + ); + assert.equal( o3.amountForSale().getAmount(), - 188045485419 * 2, - "The amount should equal 376090970838" + 7989835692, + "The amount should equal 7989835692" ); }); @@ -1140,6 +1165,81 @@ describe("CallOrder", function() { assert.equal(o1.ne(o2), false, "Orders are the same"); assert.equal(o1.equals(o2), true, "Orders are the same"); }); + + it("Calculates collateral to sell using target_collateral_ratio", function() { + let o = new CallOrder(o3_target_cr, assets, "1.3.0", settlePrice_0); + let o2 = new CallOrder( + o3_target_cr, + assets, + "1.3.113", + settlePrice_113 + ); + + /* check non-rounded values first */ + assert.equal(o._getMaxCollateralToSell(), 12542.901290883827); + assert.equal(o._getMaxDebtToCover(), 1566.1523615120586); + /* then check rounded values: */ + assert.equal(o.amountToReceive().getAmount(), 1567); // debt gets rounded up + assert.equal(o.amountToReceive().getAmount({real: true}), 0.1567); + assert.equal(o.amountForSale().getAmount(), 12550); // max_collateral_to_sell gets rounded up + + /* check non-rounded values first */ + assert.equal(o2._getMaxCollateralToSell(), 12542.901290883827); + assert.equal(o2._getMaxDebtToCover(), 1566.1523615120586); + /* then check rounded values: */ + assert.equal(o2.amountToReceive().getAmount(), 1567); // debt gets rounded up + assert.equal(o2.amountToReceive().getAmount({real: true}), 0.1567); + assert.equal(o2.amountForSale().getAmount(), 12550); // max_collateral_to_sell gets rounded up + + /* Create a new order with calculated amounts and check that CR = target_CR */ + let o3 = new CallOrder( + { + id: "1.8.2317", + borrower: "1.2.115227", + collateral: 120000 - o2.amountForSale().getAmount(), + debt: 10000 - o2.amountToReceive().getAmount(), + call_price: { + base: { + amount: "1355807223", + asset_id: "1.3.0" + }, + quote: { + amount: 349300000, + asset_id: "1.3.113" + } + }, + target_collateral_ratio: 1750 + }, + assets, + "1.3.113", + settlePrice_113 + ); + + assert.equal( + Math.floor(o3.getRatio() * 1000), + 1750, + "Collateral ratio should equal 1.750" + ); + }); + + it("Can be summed using target_cr", function() { + let o1 = new CallOrder(o3_target_cr, assets, "1.3.0", settlePrice_0); + let o2 = new CallOrder(o, assets, "1.3.0", settlePrice_0); + const o3 = o1.sum(o2); + + assert(o3.isSum); + assert.equal( + o3.amountToReceive().getAmount(), + 498820000 + 1567, + "The amount should equal 498821567" + ); + + assert.equal( + o3.amountForSale().getAmount(), + 3994917846 + 12550, + "The amount should equal 3994930396" + ); + }); }); describe("Settle Order", function() { From 96ef65a57209790144afb18c6d9f8220e6c655f9 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 09:50:34 +0200 Subject: [PATCH 42/69] #1706: Update scamAccounts list --- app/lib/common/scamAccounts.js | 599 ++++++++++++++++++++++----------- 1 file changed, 400 insertions(+), 199 deletions(-) diff --git a/app/lib/common/scamAccounts.js b/app/lib/common/scamAccounts.js index 0c404453db..80d8a9803a 100644 --- a/app/lib/common/scamAccounts.js +++ b/app/lib/common/scamAccounts.js @@ -22,230 +22,431 @@ export const scamAccountsBittrex = [ ]; export const scamAccountsOther = [ - "gateio", - "zbeoscharge1", - "pxneosincome", - "binance-btc-1", - "huobipro", - "bitpal", - "trueusd", - "zbbtc", - "bcos", - "coinegg.main", - "xbrick", - "xbrick.cny", - "xbrick.usd", - "xbrick.btc", - "coinw", - "lakebtc", - "coinexchange", - "xbtce", - "kucoin", - "quadrigacx", - "neraex", - "topbtc", "abucoins", - "coinut", - "fargobase", - "coinmate", - "nevbit", - "coinbene", - "bitpie", - "electrum", + "abucoins", + "aex-bitcny-deposit", + "aex-bts-deposit-walle", + "aida", + "aida", + "antpool", + "antpool", + "arcbit", "arcbit", "armory", - "msigna", - "coldlar", - "binance-bts-l", - "binance-bts-i", - "coinex", - "qcash", - "uncoinex", - "poim", + "armory", + "ate-io-bts", + "ate-io-bts", + "atoken", + "atoken", + "bancor.network", + "bancor.network", + "baseline", + "baseline", "bbex", - "otcx", - "u-coin", - "kkcoin", - "kkcoinwallet", - "kkcoin.wallet", - "jaxx", + "bbex", + "bcos", + "bcos", + "beechat", + "beechat", + "bepal", + "bepal", + "bibox.com", + "bibox.com", + "bigether", + "bigether", + "bigether.vip", + "bigether.vip", + "binance-btc-1", + "binance-btc-1", + "binance-bts-i", + "binance-bts-i", + "binance-bts-l", + "binance-bts-l", + "binancecleos", "bitbill", - "antpool", - "swftc", - "swftcoin", - "aida", - "secp256k1", + "bitbill", + "bitcoinindonesi", + "bitcoinindonesi", + "bitcointrade", + "bitcointrade", + "bithd", + "bithd", + "bitinka", + "bitinka", + "bitoex", + "bitoex", + "bitonic", + "bitonic", + "bitpal", + "bitpal", + "bitpesa", + "bitpesa", + "bitpie", + "bitpie", + "bits.farm", + "bits.farm", + "bitsblockchain", + "bitsblockchain", + "bitsfarm", + "bitsfarm", + "bitspark-hold", + "bitspark-hold", + "bitun", + "bitun", + "bitvip.com", + "bitvip.com", "bjex", - "www.binance.com", - "coinex.com", - "www.coinex.com", - "coin900", - "kcash", - "cointobe", - "otcbtc", - "winex.pro", + "bjex", + "blind", + "blind", + "blind-transfer", + "blind-transfer", + "blocktrade", + "btc-alpha.com", + "btc-alpha.com", + "btc.eos", + "btc.eos", + "btc38.com", + "btcmarkets.net", + "btcmarkets.net", + "bts.eos", + "bts.eos", "btsid", - "zhaobi", + "btsid", + "btsmoney", + "cex.com", + "cex.com", + "changelly", + "changelly", + "changenow", + "changenow", + "chaoex.com", + "chaoex.com", + "cobo", + "cobo", + "cohescure", + "cohescure", + "coin.space", + "coin.space", + "coin900", + "coin900", + "coin900.com", + "coin900.com", + "coinbase", + "coinbase.com", + "coinbell", + "coinbell", + "coinbene", + "coinbene", + "coinbig", + "coinbig", + "coinbig.com", + "coinbig.com", "coincode", - "yobtc", - "bitoex", + "coincode", + "coincoming", + "coincoming", + "coinegg.main", + "coinegg.main", + "coinex", + "coinex", + "coinex.com", + "coinex.com", + "coinexchange", + "coinexchange", + "coinmate", + "coinmate", + "coinrail", + "coinrail", + "coinstocks", + "coinstocks", + "cointobe", + "cointobe", + "cointome", + "cointome", + "cointopay", + "cointopay", + "coinut", + "coinut", + "coinut.com", + "coinut.com", + "coinw", + "coinw", + "coinw.com", + "coinw.com", + "coldlar", + "coldlar", + "cryptobridg", + "cryptobridg", + "cryptobridge-payout", + "cryptobridge-payout", + "ctpmall", "ctpmall", - "top.one", "ddex", + "ddex", + "decred", + "decred", + "dewone", + "dewone", + "dexko", + "dexko", + "digitaex", + "digitaex", + "door.one", + "door.one", "dragonex", - "geth", - "cex.com", - "coinw.com", - "baseline", - "wirex", - "chaoex.com", - "ourdax", - "exx.com", - "bitvip.com", - "myetherwallet", - "atoken", - "beechat", - "keepkey", - "mycelium", - "greenbits", - "coin.space", - "greenaddress", - "changelly", - "bepal", - "bitcoinindonesi", - "erc721", + "dragonex", + "eip-20", + "eip-20", + "eip20", + "eip20", + "electrum", + "electrum", + "eos.btc", + "eos.btc", + "eos.bts", + "eos.bts", + "eosfinix", + "eosfinix", + "erc-20", "erc-20", "erc-721", - "cryptobridg", - "changenow", - "coincoming", - "coin900.com", - "door.one", - "bibox.com", + "erc-721", + "erc721", + "erc721", + "etherflyer", + "etherflyer", + "etherflyer.com", + "etherflyer.com", + "ethfinex", + "ethfinex", + "expie", + "expie", + "expie.com", + "expie.com", + "exx.com", + "exx.com", + "fargobase", + "fargobase", + "forkdelta", + "forkdelta", + "gate-io-b", + "gate-io-b", + "gate-io-bt", + "gate-io-bt", + "gateio", + "gateio", + "geta-io-bts", + "geta-io-bts", + "geth", + "geth", + "greenaddress", + "greenaddress", + "greenbits", + "greenbits", + "hackers", + "hadax", + "hadax", + "hadax.com", + "hadax.com", + "hotbit", + "hotbit", + "huobipro", + "huobipro", + "ico-china", + "ico-china", + "icoape", + "icoape", + "icoape.com", + "icoape.com", + "idex", + "idex", + "idex.market", + "idex.market", + "issuer", + "issuer", + "jaxx", + "jaxx", + "kcash", + "kcash", + "keepkey", + "keepkey", + "kkcoin", + "kkcoin", + "kkcoin.wallet", + "kkcoin.wallet", + "kkcoinwallet", + "kkcoinwallet", + "koineks.com", + "koineks.com", + "koinim.com", + "koinim.com", + "kucoin", + "kucoin", + "lakebtc", + "lakebtc", + "lakebtc.com", + "lakebtc.com", + "lbank.info", "lbank.info", - "hotbit", - "qbao", - "expie", - "expie.com", - "eip20", - "eip-20", - "eos.bts", - "eos.btc", - "bts.eos", - "btc.eos", - "zhaobi.com", - "www.zhaobi.com", "licai.deposit", - "zeniex", - "richcore", - "richcore.com", - "digitaex", - "safewallet", - "tdax", - "tdax.com", - "cointome", - "bigether", - "bigether.vip", - "dexko", - "oex.com", - "hadax", - "www.hadax.com", - "hadax.com", - "cohescure", - "ico-china", - "icoape", - "icoape.com", - "coinbig", - "coinbig.com", - "bitspark-hold", - "gate-io-bt", - "ate-io-bts", - "geta-io-bts", - "yyex", - "yyex.com", - "www.yyex.com", - "yex.com", + "licai.deposit", "litepay", - "onchainfx.com", + "litepay", + "livecoi-net", + "livecoin.net", + "livecoinnet", + "locktrades", + "ls123", + "mai1100", + "mercadobitcoin", + "mercadobitcoin", + "more.top", + "more.top", + "msigna", + "msigna", + "mycelium", + "mycelium", "mycrypto", - "eosfinix", - "cobo", - "rootoken", - "bitpesa", - "cointopay", - "decred", - "wazirx", - "gate-io-b", + "mycrypto", + "myetherwallet", + "myetherwallet", + "n0stradumpus", + "neraex", + "neraex", + "neraex.pro", + "neraex.pro", + "nevbit", + "nevbit", + "oex.com", + "oex.com", + "onchainfx.com", + "onchainfx.com", + "otcbtc", + "otcbtc", + "otcx", + "otcx", + "ourdax", + "ourdax", + "p2pbucks", + "p2pbucks", "palmpay", - "coinstocks", - "blind", - "blind-transfer", + "palmpay", + "pay.bts.com", + "pay.coinbase.com", + "poim", + "poim", + "pxneosincome", + "pxneosincome", + "qbao", + "qbao", + "qcash", + "qcash", + "qtum-electrum", + "qtum-electrum", + "quadrigacx", + "quadrigacx", + "ranswiser-wallet", + "richcore", + "richcore", + "richcore.com", + "richcore.com", + "ripple.com", + "rootoken", + "rootoken", + "safewallet", + "safewallet", + "secp256k1", + "secp256k1", + "simex.global", + "simex.global", + "stealth", "stealth", - "bithd", - "cryptobridge-payout", - "zbsen", - "bits.farm", - "bitsfarm", - "idex.market", - "idex", - "etherflyer", - "etherflyer.com", - "tcash", - "dewone", - "stex.exchange", "stex", + "stex", + "stex.exchange", + "stex.exchange", + "stronghold", + "stronghold", + "swftc", + "swftc", + "swftcoin", + "swftcoin", + "tcash", + "tcash", + "tdax", + "tdax", + "tdax.com", + "tdax.com", "tokenxx", - "qtum-electrum", - "p2pbucks", - "forkdelta", - "bitsblockchain", - "bitinka", - "ethfinex", - "neraex.pro", - "simex.global", + "tokenxx", + "top.one", + "top.one", + "topbtc", + "topbtc", + "topbtc.com", "topbtc.com", - "btcmarkets.net", - "coinrail", - "lakebtc.com", - "vebitcoin", - "bancor.network", - "btc-alpha.com", - "stronghold", - "tradebytrade.com", "tradebytrade", - "mercadobitcoin", - "koineks.com", - "bitonic", - "coinut.com", - "bitcointrade", - "koinim.com", - "bitun", - "coinbell", - "more.top", - "issuer", - "ls123", - "mai1100", - "hackers", - "aex-bitcny-deposit", - "btsmoney", - "n0stradumpus", - "binancecleos", - "coinbase", - "blocktrade", - "locktrades", - "yun.bts", + "tradebytrade", + "tradebytrade.com", + "tradebytrade.com", "transwiser-walle", "transwiser-wallets", - "ranswiser-wallet", + "trueusd", + "trueusd", + "u-coin", + "u-coin", + "uncoinex", + "uncoinex", + "vebitcoin", + "vebitcoin", + "wazirx", + "wazirx", + "winex.pro", + "winex.pro", + "wirex", + "wirex", + "www.binance.com", + "www.binance.com", + "www.coinex.com", + "www.coinex.com", + "www.hadax.com", + "www.hadax.com", + "www.yyex.com", + "www.yyex.com", + "www.zhaobi.com", + "www.zhaobi.com", + "xbrick", + "xbrick", + "xbrick.btc", + "xbrick.btc", + "xbrick.cny", + "xbrick.cny", + "xbrick.usd", + "xbrick.usd", + "xbtce", + "xbtce", + "yex.com", + "yex.com", + "yobtc", + "yobtc", "yun.btc", - "pay.coinbase.com", - "pay.bts.com", - "btc38.com", + "yun.bts", "yunbi.com", - "aex-bts-deposit-walle", - "coinbase.com", - "ripple.com", - "livecoi-net", - "livecoin.net", - "livecoinnet" + "yyex", + "yyex", + "yyex.com", + "yyex.com", + "zbbtc", + "zbbtc", + "zbeoscharge1", + "zbeoscharge1", + "zbsen", + "zbsen", + "zeniex", + "zeniex", + "zhaobi", + "zhaobi", + "zhaobi.com", + "zhaobi.com" ]; From e9d609018663ce11599efa2a98d48831d5a88be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Wed, 1 Aug 2018 09:52:34 +0200 Subject: [PATCH 43/69] #1521: Update API node details (#1739) filled in more apiConfig details Signed-off-by: Stefan Schiessl --- app/api/apiConfig.js | 180 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 150 insertions(+), 30 deletions(-) diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index e7a88157a8..45bc4a2073 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -111,16 +111,21 @@ export const settingsAPIs = { { url: "wss://bitshares.openledger.info/ws", location: "Nuremberg", - region: "Western Europe", // stick to the regions that are available in nodeRegions + region: "Western Europe", country: "Germany", - operator: "OpenLedger" + operator: "Witness: openledger-dc" }, { url: "wss://eu.openledger.info/ws", location: "Berlin", - region: "Western Europe", // stick to the regions that are available in nodeRegions + region: "Western Europe", country: "Germany", - operator: "OpenLedger" + operator: "Witness: openledger-dc" + }, + { + url: "wss://openledger.hk/ws", + location: "Hong Kong", + operator: "Witness: openledger-dc" }, { url: "wss://bitshares.nu/ws", @@ -130,11 +135,11 @@ export const settingsAPIs = { }, { url: "wss://bit.btsabc.org/ws", - location: "Hong Kong" + location: "Hong Kong", + operator: "Witness: abc123" }, {url: "wss://node.btscharts.com/ws", location: "Hong Kong"}, {url: "wss://japan.bitshares.apasia.tech/ws", location: "Tokyo, Japan"}, - {url: "wss://openledger.hk/ws", location: "Hong Kong"}, { url: "wss://bitshares.crypto.fans/ws", region: "Western Europe", @@ -144,18 +149,59 @@ export const settingsAPIs = { contact: "telegram:startail" }, {url: "wss://ws.gdex.io", location: "Japan"}, - {url: "wss://ws.gdex.top", location: "China"}, - {url: "wss://dex.rnglab.org", location: "Netherlands"}, - {url: "wss://dexnode.net/ws", location: "Dallas, USA"}, - {url: "wss://la.dexnode.net/ws", location: "LA, USA"}, - {url: "wss://kc-us-dex.xeldal.com/ws", location: "Kansas City, USA"}, + { + url: "wss://ws.gdex.top", + region: "Eastern Asia", + country: "China", + location: "Shanghai", + operator: "Witness: gdex-witness", + contact: "telegram:BrianZhang" + }, + { + url: "wss://dex.rnglab.org", + location: "Netherlands", + operator: "Witness: rnglab" + }, + { + url: "wss://dexnode.net/ws", + location: "Dallas, USA", + operator: "Witness: Sahkan" + }, + { + url: "wss://la.dexnode.net/ws", + location: "LA, USA", + operator: "Witness: Sahkan" + }, + { + url: "wss://kc-us-dex.xeldal.com/ws", + location: "Kansas City, USA", + operator: "Witness: Xeldal" + }, {url: "wss://btsza.co.za:8091/ws", location: "Cape Town, South Africa"}, {url: "wss://api.bts.blckchnd.com", location: "Falkenstein, Germany"}, {url: "wss://api-ru.bts.blckchnd.com", location: "Moscow, Russia"}, {url: "wss://node.market.rudex.org", location: "Germany"}, - {url: "wss://api.bitsharesdex.com/ws", location: "Missouri, USA"}, - {url: "wss://api.fr.bitsharesdex.com/ws", location: "France"}, - {url: "wss://blockzms.xyz/ws", location: "USA"}, + { + url: "wss://api.bitsharesdex.com", + region: "Northern America", + country: "U.S.A.", + location: "Kansas City", + operator: "Witness: delegate.ihashfury", + contact: "telegram:ihashfury" + }, + { + url: "wss://api.fr.bitsharesdex.com", + region: "Western Europe", + country: "France", + location: "Paris", + operator: "Witness: delegate.ihashfury", + contact: "telegram:ihashfury" + }, + { + url: "wss://blockzms.xyz/ws", + location: "USA", + operator: "Witness: delegate-zhaomu" + }, { url: "wss://eu.nodes.bitshares.ws", region: "Western Europe", @@ -175,7 +221,11 @@ export const settingsAPIs = { country: "Singapore", operator: "Infrastructure Worker" }, - {url: "wss://ws.winex.pro", location: "Singapore"}, + { + url: "wss://ws.winex.pro", + location: "Singapore", + operator: "Witness: winex.witness" + }, { url: "wss://api.bts.mobi/ws", region: "Northern America", @@ -187,21 +237,84 @@ export const settingsAPIs = { { url: "wss://api.btsxchng.com", location: - "Global (Asia Pacific (Singapore) / US East (N. Virginia) / EU (London))" - }, - {url: "wss://api.bts.network", location: "East Coast, USA"}, - {url: "wss://btsws.roelandp.nl/ws", location: "Finland"}, - {url: "wss://api.bitshares.bhuz.info/ws", location: "Europe"}, - {url: "wss://bts-api.lafona.net/ws", location: "USA"}, - {url: "wss://kimziv.com/ws", location: "Singapore"}, - {url: "wss://api.btsgo.net/ws", location: "Singapore"}, - {url: "wss://bts.proxyhosts.info/wss", location: "Germany"}, - {url: "wss://bts.open.icowallet.net/ws", location: "Hangzhou, China"}, - {url: "wss://crazybit.online", location: "China"}, - {url: "wss://freedom.bts123.cc:15138/", location: "China"}, - {url: "wss://bitshares.bts123.cc:15138/", location: "China"}, + "Global (Asia Pacific (Singapore) / US East (N. Virginia) / EU (London))", + operator: "Witness: elmato" + }, + { + url: "wss://api.bts.network", + location: "East Coast, USA", + operator: "Witness: fox" + }, + { + url: "wss://btsws.roelandp.nl/ws", + region: "Northern Europe", + country: "Finland", + location: "Helsinki", + operator: "Witness: roelandp", + contact: "telegram:roelandp" + }, + { + url: "wss://api.bitshares.bhuz.info/ws", + location: "Europe", + operator: "Witness: bhuz" + }, + { + url: "wss://bts-api.lafona.net/ws", + location: "USA", + operator: "Witness: delegate-1.lafona" + }, + { + url: "wss://kimziv.com/ws", + region: "North America", + country: "USA", + location: "New Jersey", + operator: "Witness: witness.yao", + contact: "telegram: imyao" + }, + { + url: "wss://api.btsgo.net/ws", + location: "Singapore", + operator: "Witness: xn-delegate" + }, + { + url: "wss://bts.proxyhosts.info/wss", + location: "Germany", + operator: "Witness: verbaltech2" + }, + { + url: "wss://bts.open.icowallet.net/ws", + region: "Eastern Asia", + country: "China", + location: "Hangzhou", + operator: "Witness: magicwallet.witness", + contact: "telegram:plus_wave" + }, + { + url: "wss://crazybit.online", + location: "China", + operator: "Witness: crazybit" + }, + { + url: "wss://freedom.bts123.cc:15138/", + location: "China", + operator: "Witness: delegate.freedom" + }, + { + url: "wss://bitshares.bts123.cc:15138/", + location: "China", + operator: "Witness: delegate.freedom" + }, + { + url: "wss://api.bts.ai/", + location: "Beijing, China", + operator: "Witness: witness.hiblockchain" + }, {url: "wss://ws.hellobts.com/", location: "Japan"}, - {url: "wss://bitshares.cyberit.io/", location: "Hong Kong"}, + { + url: "wss://bitshares.cyberit.io/", + location: "Hong Kong", + operator: "Witness: witness.still" + }, { url: "wss://bts-seoul.clockwork.gr", region: "Southeastern Asia", @@ -218,7 +331,14 @@ export const settingsAPIs = { operator: "Witness: liuye", contact: "email:work@liuye.tech" }, - {url: "wss://btsfullnode.bangzi.info/ws", location: "Germany"}, + { + url: "wss://btsfullnode.bangzi.info/ws", + region: "Western Europe", + country: "Germany", + location: "Munich", + operator: "Witness: Bangzi", + contact: "telegram:Bangzi" + }, // Testnet { url: "wss://node.testnet.bitshares.eu", From 3fc08c625b92c24dda273678ad1fcb1474ad5f66 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 11:57:45 +0200 Subject: [PATCH 44/69] Change references to settings_v3 to settings_v4 --- app/stores/AccountStore.js | 2 +- app/stores/IntlStore.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/stores/AccountStore.js b/app/stores/AccountStore.js index cd69fe2caa..53eae404e2 100644 --- a/app/stores/AccountStore.js +++ b/app/stores/AccountStore.js @@ -63,7 +63,7 @@ class AccountStore extends BaseStore { accountContacts: Immutable.Set(), linkedAccounts: Immutable.Set(), // linkedAccounts are accounts for which the user controls the private keys, which are stored in a db with the wallet and automatically loaded every time the app starts referralAccount, - passwordLogin: accountStorage.get("settings_v3", { + passwordLogin: accountStorage.get("settings_v4", { passwordLogin: true }).passwordLogin }; diff --git a/app/stores/IntlStore.js b/app/stores/IntlStore.js index f06ed7fb5e..46657562ac 100644 --- a/app/stores/IntlStore.js +++ b/app/stores/IntlStore.js @@ -18,8 +18,8 @@ for (let localeCode of localeCodes) { class IntlStore { constructor() { - this.currentLocale = ss.has("settings_v3") - ? ss.get("settings_v3").locale + this.currentLocale = ss.has("settings_v4") + ? ss.get("settings_v4").locale : "en"; this.locales = ["en"]; From 7ff2c1397910c0503adb477fea91d12d467a2195 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 13:59:39 +0200 Subject: [PATCH 45/69] Two minor fixes for new settings key --- app/stores/IntlStore.js | 5 ++--- app/stores/WalletUnlockStore.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/stores/IntlStore.js b/app/stores/IntlStore.js index 46657562ac..eddd7be0a8 100644 --- a/app/stores/IntlStore.js +++ b/app/stores/IntlStore.js @@ -18,9 +18,8 @@ for (let localeCode of localeCodes) { class IntlStore { constructor() { - this.currentLocale = ss.has("settings_v4") - ? ss.get("settings_v4").locale - : "en"; + let settings = ss.get("settings_v4", {}); + this.currentLocale = settings.locale || "en"; this.locales = ["en"]; this.localesObject = {en: locale_en}; diff --git a/app/stores/WalletUnlockStore.js b/app/stores/WalletUnlockStore.js index 4489d417b6..3243dc7255 100644 --- a/app/stores/WalletUnlockStore.js +++ b/app/stores/WalletUnlockStore.js @@ -10,7 +10,7 @@ let ss = new ls(STORAGE_KEY); class WalletUnlockStore { constructor() { this.bindActions(WalletUnlockActions); - const storedSettings = ss.get("settings_v3"); + const storedSettings = ss.get("settings_v4"); let passwordLogin = "passwordLogin" in storedSettings ? storedSettings.passwordLogin From 0b258cf40550cce276bc8e5527720832ba6ab214 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 14:26:10 +0200 Subject: [PATCH 46/69] #1706: Remove duplicates and update list --- app/lib/common/scamAccounts.js | 535 ++++++++++++++++++++------------- 1 file changed, 334 insertions(+), 201 deletions(-) diff --git a/app/lib/common/scamAccounts.js b/app/lib/common/scamAccounts.js index 80d8a9803a..a50ab1aa06 100644 --- a/app/lib/common/scamAccounts.js +++ b/app/lib/common/scamAccounts.js @@ -22,431 +22,564 @@ export const scamAccountsBittrex = [ ]; export const scamAccountsOther = [ + "aacoin", "abucoins", - "abucoins", + "acinq", "aex-bitcny-deposit", "aex-bts-deposit-walle", + "aex-cnc-cza", + "aex88", + "aexdepositbm", "aida", - "aida", + "aidosmarket", + "aliant", + "alta", + "altcointrader", "antpool", - "antpool", - "arcbit", + "aporoo", + "apus", "arcbit", + "archive", "armory", - "armory", - "ate-io-bts", "ate-io-bts", "atoken", - "atoken", + "azex", + "b2bx", "bancor.network", - "bancor.network", - "baseline", + "barterdex", "baseline", "bbex", - "bbex", + "bbts001", + "bc1q", + "bcoin", "bcos", - "bcos", - "beechat", "beechat", "bepal", - "bepal", + "bft-dpos", + "bgogo", + "bhex", "bibox.com", - "bibox.com", - "bigether", + "bigbag", "bigether", "bigether.vip", - "bigether.vip", + "bilaxy", "binance-btc-1", - "binance-btc-1", - "binance-bts-i", "binance-bts-i", "binance-bts-l", - "binance-bts-l", "binancecleos", + "bishengtopex", + "bisq", + "bisq.network", + "bitarg", + "bitasiaex", "bitbill", - "bitbill", - "bitcoinindonesi", + "bitbill.app", + "bitbns", "bitcoinindonesi", "bitcointrade", - "bitcointrade", + "bitfinexdep1", + "bitflip", + "bitflyer.com", "bithd", - "bithd", - "bitinka", + "bitholic", "bitinka", - "bitoex", + "bitkk", + "bitkkchubei00", + "bitkkchubei001", + "bitkkchubei02", + "bitkonan", + "bitkop", + "bitmaszyna", "bitoex", "bitonic", - "bitonic", - "bitpal", + "bitopro", + "bitpaction", "bitpal", "bitpesa", - "bitpesa", - "bitpie", "bitpie", + "bitrefill", "bits.farm", - "bits.farm", - "bitsblockchain", "bitsblockchain", "bitsfarm", - "bitsfarm", + "bitshares-app", + "bitshares.app", "bitspark-hold", - "bitspark-hold", - "bitun", "bitun", - "bitvip.com", + "bitupro", "bitvip.com", "bjex", - "bjex", - "blind", + "bkex", "blind", "blind-transfer", - "blind-transfer", "blocktrade", + "bloex", + "blox", + "bsend001", "btc-alpha.com", - "btc-alpha.com", - "btc.eos", "btc.eos", "btc38.com", + "btcalph", "btcmarkets.net", - "btcmarkets.net", + "btcxindia", + "btex", + "bts.app", "bts.eos", - "bts.eos", - "btsid", + "btsalpha", "btsid", "btsmoney", + "burstnation", + "buyucoin", + "buyucoin-walle", + "c-patex", + "cashaddr", + "cashierest", + "cetus", "cex.com", - "cex.com", + "chaince", + "chaince.com", + "chainceoneos", "changelly", - "changelly", - "changenow", "changenow", "chaoex.com", - "chaoex.com", + "citcon", "cobo", - "cobo", - "cohescure", + "cobowalletcn", + "cobowalletio", "cohescure", "coin.space", - "coin.space", + "coin2co", "coin900", - "coin900", - "coin900.com", "coin900.com", "coinbase", "coinbase.com", + "coinbe", "coinbell", - "coinbell", - "coinbene", "coinbene", "coinbig", - "coinbig", - "coinbig.com", "coinbig.com", "coincode", - "coincode", "coincoming", - "coincoming", - "coinegg.main", + "coineal", "coinegg.main", "coinex", - "coinex", "coinex.com", - "coinex.com", - "coinexchange", "coinexchange", + "coinexmarket", + "coinfloorex", + "coingeto", + "coinhouse", + "coinhub", + "coinlink", "coinmate", - "coinmate", + "coinoah", + "coinoah.com", + "coinpark", "coinrail", - "coinrail", - "coinstocks", + "coinsave", "coinstocks", - "cointobe", + "cointiger-deposit-bts", + "cointiger-deposit-bts0", + "cointiger-deposit-bts1", "cointobe", "cointome", - "cointome", - "cointopay", "cointopay", "coinut", - "coinut", "coinut.com", - "coinut.com", - "coinw", "coinw", "coinw.com", - "coinw.com", + "coinyee", "coldlar", - "coldlar", - "cryptobridg", + "committee-101", + "committee-102", + "committee-103", + "committee-104", + "committee-105", + "committee-106", + "committee-107", + "committee-108", + "committee-109", + "committee-110", + "committee-accou", + "committee-cnytrade", + "committee-usdoperato", + "contractland", + "counterwallet", + "crux", "cryptobridg", "cryptobridge-payout", - "cryptobridge-payout", + "cryptoderivatives", + "cryptoderivatives.market", + "cryptomkt", + "cryptomkt.com", + "crypton", + "cryptonize", + "crypviser", "ctpmall", - "ctpmall", - "ddex", + "cx-bitcny-deposit-wallet", + "cx-bitcny-withdraw-wallet", + "cx-bts-deposit-wallet", + "cx-bts-withdraw-wallet", + "daex", + "dax-deposit", + "dax-exchange", + "dax-mn", + "dax-withdraw", "ddex", "decred", - "decred", - "dewone", "dewone", + "dex.top", "dexko", - "dexko", - "digitaex", + "dgtmarket", + "diceex", + "diceex-bit", + "diceex-bitcn", + "diceex-bitusd", + "diceex-btc", + "diceex-cny", + "dig-exchange", + "digifinex", "digitaex", "door.one", - "door.one", "dragonex", - "dragonex", - "eip-20", + "eclair", + "ecoex-bts-1", + "eidoo", "eip-20", "eip20", - "eip20", "electrum", - "electrum", - "eos.btc", + "eligma", + "entapay", + "enumivo", "eos.btc", "eos.bts", - "eos.bts", + "eosdac", "eosfinix", - "eosfinix", - "erc-20", "erc-20", "erc-721", - "erc-721", "erc721", - "erc721", - "etherflyer", "etherflyer", "etherflyer.com", - "etherflyer.com", "ethfinex", - "ethfinex", - "expie", + "ewex", + "excambriorex", + "exnow", "expie", "expie.com", - "expie.com", + "exvo", "exx.com", - "exx.com", - "fargobase", + "exxbtc001", + "exxbts00", + "exxbts01", + "exxsend00", + "exxsend01", + "ezbtc", "fargobase", + "fhex", + "firefoxotc", "forkdelta", - "forkdelta", + "freiexchange", "gate-io-b", - "gate-io-b", - "gate-io-bt", "gate-io-bt", + "gate-io-btc", "gateio", - "gateio", - "geta-io-bts", + "gateiowallet", + "gcox", + "gdexioforeos", + "geos", "geta-io-bts", "geth", - "geth", - "greenaddress", + "ggex", + "glidera", "greenaddress", "greenbits", - "greenbits", + "grus", + "guldentrader", "hackers", "hadax", - "hadax", - "hadax.com", "hadax.com", + "hbus", + "hcoin", + "heatwallet", + "heatwallet.com", + "heztanrqgene", + "hitbtc-exchang", + "hitbtc.exchange", "hotbit", - "hotbit", + "huobi-bts-deposi", + "huobi-deposi", + "huobideposit", "huobipro", - "huobipro", - "ico-china", + "iceex-bitcny", "ico-china", "icoape", - "icoape", "icoape.com", - "icoape.com", - "idex", + "idax", + "idax-deposi", + "idax-exchang", + "idax-nm", + "idax-withdra", + "idax.deposit", + "idax.exchange", + "idax.withdraw", "idex", "idex.market", - "idex.market", + "idle", + "ifish", + "independentreserve", + "indodax", + "indus", + "infinitycoin", + "infinitycoin.exchange", + "iquant", "issuer", - "issuer", - "jaxx", + "itbtc-exchange", "jaxx", - "kcash", + "jrex", + "kairex", "kcash", "keepkey", - "keepkey", - "kkcoin", "kkcoin", "kkcoin.wallet", - "kkcoin.wallet", "kkcoinwallet", - "kkcoinwallet", - "koineks.com", "koineks.com", "koinim.com", - "koinim.com", + "krakenkraken", "kucoin", - "kucoin", - "lakebtc", "lakebtc", "lakebtc.com", - "lakebtc.com", - "lbank.info", + "latoken", "lbank.info", + "leoxchange", "licai.deposit", - "licai.deposit", - "litepay", + "liteforex", "litepay", + "liteshares", "livecoi-net", "livecoin.net", "livecoinnet", + "llex", "locktrades", + "loois", + "loom", "ls123", + "luckygame", + "luckygames", + "luckygames-i", + "lupus", + "lykke.com", + "lyra", "mai1100", + "mark.space", + "meet-up", + "meet.one", + "meetup", + "memo.cash", + "mensa", "mercadobitcoin", - "mercadobitcoin", + "metamask", + "mexc", + "mmex", "more.top", - "more.top", - "msigna", + "morphtoken", "msigna", "mycelium", - "mycelium", "mycrypto", - "mycrypto", - "myetherwallet", + "mydicewallet", + "mydicewallet.com", "myetherwallet", + "mywallet-1023", "n0stradumpus", - "neraex", + "nanex", + "negociecoins", "neraex", "neraex.pro", - "neraex.pro", - "nevbit", "nevbit", + "new.one", + "nicehash", + "nix-e", + "nocks", + "oasisdex", + "obit-wallet", + "octaex", + "ocx-bitcny-deposit-walle", + "ocx-bitcny-withdraw-walle", + "ocx-bts-deposit-walle", + "ocx-bts-withdraw-walle", "oex.com", - "oex.com", + "ointiger-deposit-bts01", + "ojbk", + "okbtothemoon", + "okcoinkr", + "omicrex", + "ommittee-account", + "omniexplorer", + "omniexplorer.info", + "onchainfx", "onchainfx.com", - "onchainfx.com", - "otcbtc", + "ooex", + "ooobtc", "otcbtc", - "otcx", + "otcbtcdotcom", + "otcbtcdotnet", + "otcwallet", "otcx", "ourdax", - "ourdax", - "p2pbucks", + "ovis", "p2pbucks", "palmpay", - "palmpay", + "paradex", + "pavo", "pay.bts.com", "pay.coinbase.com", + "paymium", + "pieotc", + "pinocaitoken", + "pocketeos", "poim", - "poim", - "pxneosincome", + "pomelo", + "protokenbank", + "pxn-eos", + "pxn-incom", + "pxn.eos", + "pxn.one", + "pxneos", + "pxneos-income", "pxneosincome", - "qbao", + "pxnincome", + "pyxis", "qbao", "qcash", - "qcash", - "qtum-electrum", + "qlink", "qtum-electrum", "quadrigacx", - "quadrigacx", + "rabobit", + "radarrelay", + "radarrelay.com", "ranswiser-wallet", - "richcore", + "referrer", + "renrenbit", "richcore", "richcore.com", - "richcore.com", + "rippex", "ripple.com", + "ripplechina.net", + "ripplefox", "rootoken", - "rootoken", - "safewallet", + "rrex", + "rudexgateway", "safewallet", "secp256k1", - "secp256k1", - "simex.global", + "sendy", "simex.global", + "sistemkoin", + "spectrocoin", "stealth", - "stealth", + "stellarterm", + "stellarterm.com", "stex", - "stex", - "stex.exchange", "stex.exchange", "stronghold", - "stronghold", + "superleague1", + "swft.pro", "swftc", - "swftc", - "swftcoin", "swftcoin", - "tcash", + "tcalpha", "tcash", "tdax", - "tdax", - "tdax.com", "tdax.com", - "tokenxx", + "tdex", + "therocktrading", + "therocktrading.com", + "thinkbit", + "tidebit", + "token.store", + "token360", + "token365", + "tokenlon", "tokenxx", "top.one", - "top.one", - "topbtc", "topbtc", "topbtc.com", - "topbtc.com", + "toshi", "tradebytrade", - "tradebytrade", - "tradebytrade.com", "tradebytrade.com", + "tradeogre", + "tradesatoshi.com", "transwiser-walle", "transwiser-wallets", + "truecoin", "trueusd", - "trueusd", + "trusty.fund", + "tusd", + "tuxexchange", + "tuxexchange.com", "u-coin", - "u-coin", - "uncoinex", + "uckygames-io", + "unblock", "uncoinex", + "unicode", + "uniex", + "uobi-bts-deposit", + "uobi-deposit", + "upbitwallets", + "usadae", + "usadae.com", + "usdc", + "utxo", + "uuex", + "uyucoin-wallet", "vebitcoin", - "vebitcoin", - "wazirx", + "vela", + "virtacoinworld", + "vuniyuoxoeub", + "vvbtc", + "walletdunamu", "wazirx", + "wetez", "winex.pro", - "winex.pro", - "wirex", "wirex", "www.binance.com", - "www.binance.com", "www.coinex.com", - "www.coinex.com", - "www.hadax.com", "www.hadax.com", - "www.yyex.com", + "www.usadae.com", "www.yyex.com", "www.zhaobi.com", - "www.zhaobi.com", - "xbrick", "xbrick", "xbrick.btc", - "xbrick.btc", "xbrick.cny", - "xbrick.cny", - "xbrick.usd", "xbrick.usd", "xbtce", - "xbtce", + "xdaex", + "xdag", + "xn-income", + "xxbts001", + "xxsend001", "yex.com", - "yex.com", - "yobtc", + "yhex", + "yobit-wall", + "yobit-walle", "yobtc", "yun.btc", "yun.bts", "yunbi.com", - "yyex", + "yuxiao", "yyex", "yyex.com", - "yyex.com", - "zbbtc", + "z-201", "zbbtc", - "zbeoscharge1", + "zbbtc001", + "zbbts00", + "zbbts01", "zbeoscharge1", "zbsen", - "zbsen", - "zeniex", + "zbsend00", + "zbsend01", + "zecoex", + "zecoex-btc", + "zecoex-bts", "zeniex", "zhaobi", - "zhaobi", "zhaobi.com", - "zhaobi.com" + "zhex", + "zilla" ]; From 284bf838e8e9461a562298bae501b0d88c61b7c2 Mon Sep 17 00:00:00 2001 From: svk Date: Wed, 1 Aug 2018 14:28:14 +0200 Subject: [PATCH 47/69] Fix #1740: Add pagination to several tables (#1741) * Create new PaginatedList component * Add pagination to Assets and Accounts * Add pagination to AccountOrders, portfolio, recent transactions --- app/assets/locales/locale-de.json | 8 + app/assets/locales/locale-en.json | 11 +- app/assets/locales/locale-es.json | 8 + app/assets/locales/locale-fr.json | 8 + app/assets/locales/locale-it.json | 8 + app/assets/locales/locale-ja.json | 8 + app/assets/locales/locale-ko.json | 8 + app/assets/locales/locale-ru.json | 8 + app/assets/locales/locale-tr.json | 8 + app/assets/locales/locale-zh.json | 8 + app/components/Account/AccountOrders.jsx | 49 ++- app/components/Account/AccountOverview.jsx | 372 ++++++++---------- .../Account/AccountPortfolioList.jsx | 234 ++++++----- app/components/Account/RecentTransactions.jsx | 33 +- app/components/Exchange/MyOpenOrders.jsx | 50 ++- app/components/Explorer/Accounts.jsx | 97 +++-- app/components/Explorer/Assets.jsx | 93 ++--- app/components/Utility/PaginatedList.jsx | 91 +++++ 18 files changed, 617 insertions(+), 485 deletions(-) create mode 100644 app/components/Utility/PaginatedList.jsx diff --git a/app/assets/locales/locale-de.json b/app/assets/locales/locale-de.json index 5f53aec54f..3f1023550c 100644 --- a/app/assets/locales/locale-de.json +++ b/app/assets/locales/locale-de.json @@ -643,6 +643,9 @@ "unclaimed_issuer_income": "Nicht ausgezahlte Herausgeberanteile" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { @@ -1820,6 +1823,11 @@ "expire": "Your transaction has expired without being confirmed, please try again later." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Platzieren Sie Kaufaufträge über dieses Formular.", "buy_orders": "Sehen Sie alle Kaufaufträge für diesen Markt an.", diff --git a/app/assets/locales/locale-en.json b/app/assets/locales/locale-en.json index 92735eb540..deec2b3c49 100644 --- a/app/assets/locales/locale-en.json +++ b/app/assets/locales/locale-en.json @@ -620,9 +620,6 @@ "title": "Accounts" }, "asset": { - "feed_producer": "Feed producer", - "feed_producer_text": - "Approved feed producers may publish a new feed using the form below:", "actions": "Asset actions", "fee_pool": { "claim_balance": "Claim fee pool balance", @@ -641,6 +638,9 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { @@ -1819,6 +1819,11 @@ "expire": "Your transaction has expired without being confirmed, please try again later." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Place buy orders using this form.", "buy_orders": "View all buy orders for this market.", diff --git a/app/assets/locales/locale-es.json b/app/assets/locales/locale-es.json index e31958a8db..ee873c764f 100644 --- a/app/assets/locales/locale-es.json +++ b/app/assets/locales/locale-es.json @@ -650,6 +650,9 @@ "title": "Fondo de Comisiones", "unclaimed_issuer_income": "Ingresos del emisor no reclamados" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { @@ -1850,6 +1853,11 @@ "expire": "Su transacción ha expirado sin confirmación, intente de nuevo más tarde." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Coloque las órdenes de compra usando este formulario.", "buy_orders": "Ver todas las órdenes de compra para este mercado.", diff --git a/app/assets/locales/locale-fr.json b/app/assets/locales/locale-fr.json index 77065a9e91..c521f691aa 100644 --- a/app/assets/locales/locale-fr.json +++ b/app/assets/locales/locale-fr.json @@ -638,6 +638,9 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { @@ -1819,6 +1822,11 @@ "expire": "Your transaction has expired without being confirmed, please try again later." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Placez les ordres d'achat en utilisant ce formulaire.", "buy_orders": "Voir toutes les commandes d'achat pour ce marché.", diff --git a/app/assets/locales/locale-it.json b/app/assets/locales/locale-it.json index 8e7a3eaf89..ff85601c09 100644 --- a/app/assets/locales/locale-it.json +++ b/app/assets/locales/locale-it.json @@ -648,6 +648,9 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Reddito dell'erogatore non riscosso" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "Il nome di asset %(name)s non è valido", "margin_positions": { @@ -1846,6 +1849,11 @@ "expire": "La tua transazione è scaduta senza essere stata confermata; per favore riprova più tardi." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Inserisci ordini di acquisto utilizzando questo modulo.", "buy_orders": diff --git a/app/assets/locales/locale-ja.json b/app/assets/locales/locale-ja.json index 32af08f04d..4652f4bd36 100644 --- a/app/assets/locales/locale-ja.json +++ b/app/assets/locales/locale-ja.json @@ -638,6 +638,9 @@ "title": "手数料プール", "unclaimed_issuer_income": "未請求の発行者収入" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "アセット名%(name)sは無効です", "margin_positions": { @@ -1812,6 +1815,11 @@ "expire": "あなたのトランザクションは確認されずに期限切れになりました。後でやり直してください。" }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "このフォームを使用して買い注文を出します。", "buy_orders": "この市場のすべての買い注文を表示する。", diff --git a/app/assets/locales/locale-ko.json b/app/assets/locales/locale-ko.json index a8446429fe..7408526189 100644 --- a/app/assets/locales/locale-ko.json +++ b/app/assets/locales/locale-ko.json @@ -638,6 +638,9 @@ "title": "Fee Pool", "unclaimed_issuer_income": "Unclaimed issuer income" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { @@ -1807,6 +1810,11 @@ "expire": "Your transaction has expired without being confirmed, please try again later." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "이 양식을 사용하여 구매 주문을하십시오.", "buy_orders": "이 시장에 대한 모든 구매 주문을보십시오.", diff --git a/app/assets/locales/locale-ru.json b/app/assets/locales/locale-ru.json index 2ae604b16f..24b0cf2334 100644 --- a/app/assets/locales/locale-ru.json +++ b/app/assets/locales/locale-ru.json @@ -652,6 +652,9 @@ "title": "Пул комиссии", "unclaimed_issuer_income": "Невостребованный доход эмитента\n" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "Недопустимое имя %(name)s актива", "margin_positions": { @@ -1855,6 +1858,11 @@ "expire": "Срок ожидания Вашей транзакции истек без подтверждения, пожалуйста, повторите попытку позже." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Разместить заявки на покупку, используя эту форму.", "buy_orders": "Просмотреть все заявки на покупку для этого рынка.", diff --git a/app/assets/locales/locale-tr.json b/app/assets/locales/locale-tr.json index c0b34644ec..61fee7463f 100644 --- a/app/assets/locales/locale-tr.json +++ b/app/assets/locales/locale-tr.json @@ -644,6 +644,9 @@ "title": "Ücret Havuzu", "unclaimed_issuer_income": "Talep edilmemiş ihraççı geliri" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "The asset name %(name)s is invalid", "margin_positions": { @@ -1825,6 +1828,11 @@ "expire": "Your transaction has expired without being confirmed, please try again later." }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "Bu formu kullanarak satın alma siparişleri verin.", "buy_orders": "Bu pazar için tüm satınalma siparişlerini görüntüleyin.", diff --git a/app/assets/locales/locale-zh.json b/app/assets/locales/locale-zh.json index 0821bf4513..f93725e1d1 100644 --- a/app/assets/locales/locale-zh.json +++ b/app/assets/locales/locale-zh.json @@ -620,6 +620,9 @@ "title": "手续费资金池", "unclaimed_issuer_income": "发行人未申领收入" }, + "feed_producer": "Feed producer", + "feed_producer_text": + "Approved feed producers may publish a new feed using the form below:", "info": "Asset info", "invalid": "资产名 %(name)s 无效", "margin_positions": { @@ -1748,6 +1751,11 @@ "trx_error": { "expire": "你的交易确认超时,请稍后尝试。" }, + "utility": { + "total_x_assets": "Total of %(count)s assets", + "total_x_items": "Total of %(count)s items", + "total_x_operations": "Total of %(count)s operations" + }, "walkthrough": { "buy_form": "使用此表格下订单", "buy_orders": "查看该市场的所有购买订单。", diff --git a/app/components/Account/AccountOrders.jsx b/app/components/Account/AccountOrders.jsx index f815d065ca..662e0d3f79 100644 --- a/app/components/Account/AccountOrders.jsx +++ b/app/components/Account/AccountOrders.jsx @@ -9,6 +9,7 @@ import SettingsStore from "stores/SettingsStore"; import SettingsActions from "actions/SettingsActions"; import marketUtils from "common/market_utils"; import Translate from "react-translate-component"; +import PaginatedList from "../Utility/PaginatedList"; class AccountOrders extends React.Component { constructor(props) { @@ -235,21 +236,29 @@ class AccountOrders extends React.Component { let tables = []; - let marketIndex = 0; for (let market in marketOrders) { if (marketOrders[market].length) { - tables.push( -
    H
    H
    - - {tables} - {this.props.children} -
    + + } + rows={tables} + extraRow={this.props.children} + />
    ); } diff --git a/app/components/Account/AccountOverview.jsx b/app/components/Account/AccountOverview.jsx index 0a1ff1b13b..02a4f61d0b 100644 --- a/app/components/Account/AccountOverview.jsx +++ b/app/components/Account/AccountOverview.jsx @@ -9,7 +9,6 @@ import Proposals from "components/Account/Proposals"; import {ChainStore} from "bitsharesjs"; import SettingsActions from "actions/SettingsActions"; import utils from "common/utils"; - import {Tabs, Tab} from "../Utility/Tabs"; import AccountOrders from "./AccountOrders"; import cnames from "classnames"; @@ -113,6 +112,111 @@ class AccountOverview extends React.Component { } } + getHeader() { + let {settings} = this.props; + let {shownAssets} = this.state; + + const preferredUnit = + settings.get("unit") || this.props.core_asset.get("symbol"); + const showAssetPercent = settings.get("showAssetPercent", false); + + return ( + + + + + + + + + () + + + + + + + + {showAssetPercent ? ( + + + + ) : null} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } + render() { let {account, hiddenAssets, settings, orders} = this.props; let {shownAssets} = this.state; @@ -130,7 +234,7 @@ class AccountOverview extends React.Component { if (account.toJS && account.has("call_orders")) call_orders = account.get("call_orders").toJS(); - let includedBalances, hiddenBalances; + let includedPortfolioList, hiddenPortfolioList; let account_balances = account.get("balances"); let includedBalancesList = Immutable.List(), hiddenBalancesList = Immutable.List(); @@ -207,53 +311,6 @@ class AccountOverview extends React.Component { includedBalancesList = includedBalancesList.push(a); } }); - - let included = ( - - ); - - includedBalances = included; - - let hidden = ( - - ); - - hiddenBalances = hidden; } let portfolioHiddenAssetsBalance = ( @@ -337,7 +394,49 @@ class AccountOverview extends React.Component { ); - let showAssetPercent = settings.get("showAssetPercent", false); + includedPortfolioList = ( + + ); + + hiddenPortfolioList = ( + + ); // add unicode non-breaking space as subtext to Activity Tab to ensure that all titles are aligned // horizontally @@ -425,137 +524,12 @@ class AccountOverview extends React.Component {
    {shownAssets != "visual" ? ( - - - - - - - - - {showAssetPercent ? ( - - ) : null} - - - - - - - - - - - - {shownAssets == "hidden" && - hiddenBalancesList.size - ? hiddenBalances - : includedBalances} - - - {shownAssets == "hidden" && - hiddenBalancesList.size - ? hiddenPortfolioBalance - : includedPortfolioBalance} - -
    - - - - - {" "} - () - - - - - - - - - - - - - - - - - - - - - - - - -
    + shownAssets === "hidden" && + hiddenBalancesList.size ? ( + hiddenPortfolioList + ) : ( + includedPortfolioList + ) ) : ( - - - - {totalValueText} - - - {ordersValue} - - {this.props.isMyAccount ? ( - - ) : null} - - + + + {totalValueText} + + + {ordersValue} + + {this.props.isMyAccount ? : null} + @@ -639,7 +609,7 @@ class AccountOverview extends React.Component { compactView={false} showMore={true} fullHeight={true} - limit={15} + limit={100} showFilters={true} dashboard /> diff --git a/app/components/Account/AccountPortfolioList.jsx b/app/components/Account/AccountPortfolioList.jsx index 568592c1d3..536fc73ebf 100644 --- a/app/components/Account/AccountPortfolioList.jsx +++ b/app/components/Account/AccountPortfolioList.jsx @@ -11,7 +11,7 @@ import LinkToAssetById from "../Utility/LinkToAssetById"; import BorrowModal from "../Modal/BorrowModal"; import ReactTooltip from "react-tooltip"; import {getBackedCoin} from "common/gatewayUtils"; -import {ChainStore} from "bitsharesjs/es"; +import {ChainStore} from "bitsharesjs"; import {connect} from "alt-react"; import SettingsStore from "stores/SettingsStore"; import GatewayStore from "stores/GatewayStore"; @@ -29,6 +29,8 @@ import WithdrawModal from "../Modal/WithdrawModalNew"; import ZfApi from "react-foundation-apps/src/utils/foundation-api"; import ReserveAssetModal from "../Modal/ReserveAssetModal"; import BaseModal from "../Modal/BaseModal"; +import PaginatedList from "../Utility/PaginatedList"; +import MarketUtils from "common/market_utils"; class AccountPortfolioList extends React.Component { constructor() { @@ -121,42 +123,40 @@ class AccountPortfolioList extends React.Component { return 0; }, priceValue: function(a, b) { - let aRef = this.priceRefs[a.key]; - let bRef = this.priceRefs[b.key]; - if (aRef && bRef) { - let aPrice = aRef.getFinalPrice(true); - let bPrice = bRef.getFinalPrice(true); - if (aPrice === null && bPrice !== null) return 1; - if (aPrice !== null && bPrice === null) return -1; - if (aPrice === null && bPrice === null) - return this.sortFunctions.alphabetic(a, b, true); + let aPrice = this.priceRefs[a.key]; + let bPrice = this.priceRefs[b.key]; + if (aPrice && bPrice) { return this.props.sortDirection ? aPrice - bPrice : bPrice - aPrice; + } else if (aPrice === null && bPrice !== null) { + return 1; + } else if (aPrice !== null && bPrice === null) { + return -1; + } else { + return this.sortFunctions.alphabetic(a, b, true); } }, totalValue: function(a, b) { - let aRef = this.valueRefs[a.key]; - let bRef = this.valueRefs[b.key]; - if (aRef && bRef) { - let aValue = aRef.getValue(); - let bValue = bRef.getValue(); - if (!aValue && bValue) return 1; - if (aValue && !bValue) return -1; - if (!aValue && !bValue) - return this.sortFunctions.alphabetic(a, b, true); + let aValue = this.valueRefs[a.key]; + let bValue = this.valueRefs[b.key]; + if (aValue && bValue) { return this.props.sortDirection ? aValue - bValue : bValue - aValue; + } else if (!aValue && bValue) { + return 1; + } else if (aValue && !bValue) { + return -1; + } else { + return this.sortFunctions.alphabetic(a, b, true); } }, changeValue: function(a, b) { - let aRef = this.changeRefs[a.key]; - let bRef = this.changeRefs[b.key]; + let aValue = this.changeRefs[a.key]; + let bValue = this.changeRefs[b.key]; - if (aRef && bRef) { - let aValue = aRef.getValue(); - let bValue = bRef.getValue(); + if (aValue && bValue) { let aChange = parseFloat(aValue) != "NaN" ? parseFloat(aValue) : aValue; let bChange = @@ -408,11 +408,42 @@ class AccountPortfolioList extends React.Component { const canBuy = !!this.props.bridgeCoins.get(symbol); const assetAmount = balanceObject.get("balance"); + /* Sorting refs */ this.qtyRefs[asset.get("symbol")] = utils.get_asset_amount( assetAmount, asset ); + let preferredAsset = ChainStore.getAsset(preferredUnit); + this.valueRefs[asset.get("symbol")] = + hasBalance && !!preferredAsset + ? MarketUtils.convertValue( + assetAmount, + preferredAsset, + asset, + this.props.allMarketStats, + this.props.coreAsset, + true + ) + : null; + + this.priceRefs[asset.get("symbol")] = !preferredAsset + ? null + : MarketUtils.getFinalPrice( + this.props.coreAsset, + asset, + preferredAsset, + this.props.allMarketStats, + true + ); + + let marketId = asset.get("symbol") + "_" + preferredUnit; + let currentMarketStats = this.props.allMarketStats.get(marketId); + this.changeRefs[asset.get("symbol")] = + currentMarketStats && currentMarketStats.change + ? currentMarketStats.change + : 0; + balances.push( @@ -428,11 +459,6 @@ class AccountPortfolioList extends React.Component { className="column-hide-small" > { - if (c && c.refs.bound_component) - this.priceRefs[asset.get("symbol")] = - c.refs.bound_component; - }} fromAsset={asset.get("id")} pulsate={{reverse: true, fill: "forwards"}} hide_symbols @@ -443,14 +469,9 @@ class AccountPortfolioList extends React.Component { className="column-hide-small" > { - if (c && c.refs.bound_component) - this.changeRefs[asset.get("symbol")] = - c.refs.bound_component; - }} base={asset.get("id")} quote={preferredUnit} - marketId={asset.get("symbol") + "_" + preferredUnit} + marketId={marketId} hide_symbols /> @@ -463,11 +484,6 @@ class AccountPortfolioList extends React.Component { balance={balance} toAsset={preferredUnit} hide_asset - refCallback={c => { - if (c && c.refs.bound_component) - this.valueRefs[asset.get("symbol")] = - c.refs.bound_component; - }} /> ) : null} @@ -870,71 +886,79 @@ class AccountPortfolioList extends React.Component { this.props.bridgeCoins.get(this.state.bridgeAsset) || null; return ( - - {this._renderBalances( - this.props.balanceList, - this.props.optionalAssets, - this.props.visible - )} - {this._renderSendModal()} - {this._renderSettleModal()} - {/* Withdraw Modal*/} - - - - - {/* Deposit Modal */} - - - {/* Bridge modal */} - - - {/* Burn modal */} - -
    -
    - { - ZfApi.publish("reserve_asset", "close"); - }} - /> -
    -
    - +
    + + {this._renderSendModal()} + {this._renderSettleModal()} + {/* Withdraw Modal*/} + + + + + {/* Deposit Modal */} + + + {/* Bridge modal */} + + + {/* Burn modal */} + +
    +
    + { + ZfApi.publish("reserve_asset", "close"); + }} + /> +
    +
    +
    +
    ); } } diff --git a/app/components/Account/RecentTransactions.jsx b/app/components/Account/RecentTransactions.jsx index 078053dd64..6dd9b16910 100644 --- a/app/components/Account/RecentTransactions.jsx +++ b/app/components/Account/RecentTransactions.jsx @@ -6,16 +6,14 @@ import ChainTypes from "../Utility/ChainTypes"; import BindToChainState from "../Utility/BindToChainState"; import utils from "common/utils"; import {ChainTypes as grapheneChainTypes} from "bitsharesjs"; -import TransitionWrapper from "../Utility/TransitionWrapper"; import ps from "perfect-scrollbar"; import counterpart from "counterpart"; import Icon from "../Icon/Icon"; import cnames from "classnames"; import PropTypes from "prop-types"; - +import PaginatedList from "../Utility/PaginatedList"; const {operations} = grapheneChainTypes; const alignLeft = {textAlign: "left"}; -const alignRight = {textAlign: "right"}; function compareOps(b, a) { if (a.block_num === b.block_num) { @@ -49,7 +47,7 @@ class RecentTransactions extends React.Component { constructor(props) { super(); this.state = { - limit: props.limit || 20, + limit: props.limit, csvExport: false, headerHeight: 85, filter: "all" @@ -298,7 +296,7 @@ class RecentTransactions extends React.Component { ]; - display_history.push( + let action = ( {historyCount > 0 ? ( @@ -321,7 +319,7 @@ class RecentTransactions extends React.Component { ) : null} - +  {(this.props.showMore && historyCount > this.props.limit) || (20 && limit < historyCount) ? ( @@ -334,6 +332,7 @@ class RecentTransactions extends React.Component { ) : null} + ); @@ -386,7 +385,8 @@ class RecentTransactions extends React.Component { } ref="transactions" > - - + header={ - - - - {display_history} - -
    +
    + } + rows={display_history} + withTransition + label="utility.total_x_operations" + extraRow={action} + />
    {historyCount > 0 && this.state.csvExport && ( diff --git a/app/components/Exchange/MyOpenOrders.jsx b/app/components/Exchange/MyOpenOrders.jsx index 18eed11927..3dedb489c8 100644 --- a/app/components/Exchange/MyOpenOrders.jsx +++ b/app/components/Exchange/MyOpenOrders.jsx @@ -65,33 +65,31 @@ class TableHeader extends React.Component { ) : ( - - - {isMyAccount ? ( - - - - ) : null} - - - - - - - - - - - - - - - - - + + {isMyAccount ? ( + + - - + ) : null} + + + + + + + + + + + + + + + + + + + ); } } diff --git a/app/components/Explorer/Accounts.jsx b/app/components/Explorer/Accounts.jsx index 2fb77c2738..661b167fa5 100644 --- a/app/components/Explorer/Accounts.jsx +++ b/app/components/Explorer/Accounts.jsx @@ -12,6 +12,7 @@ import BalanceComponent from "../Utility/BalanceComponent"; import AccountStore from "stores/AccountStore"; import {connect} from "alt-react"; import LoadingIndicator from "../LoadingIndicator"; +import PaginatedList from "../Utility/PaginatedList"; class AccountRow extends React.Component { static propTypes = { @@ -142,7 +143,7 @@ class Accounts extends React.Component { render() { let {searchAccounts} = this.props; let {searchTerm} = this.state; - let accountRows = null; + let accountRows = []; if (searchAccounts.size > 0 && searchTerm && searchTerm.length > 0) { accountRows = searchAccounts @@ -187,57 +188,49 @@ class Accounts extends React.Component { onChange={this._onSearchChange.bind(this)} />
    -
    - - - - - - - - - - - - - {this.state.isLoading ? ( - - ) : ( - accountRows - )} - -
    - - - - - - - - - -
    - {this.state.isLoading ? ( -
    - -
    - ) : null} -
    + + + + + + + + + + + + + + + + + + } + rows={accountRows} + pageSize={20} + /> + {this.state.isLoading ? ( +
    + +
    + ) : null}
    ); diff --git a/app/components/Explorer/Assets.jsx b/app/components/Explorer/Assets.jsx index cf75e262a0..12566de46b 100644 --- a/app/components/Explorer/Assets.jsx +++ b/app/components/Explorer/Assets.jsx @@ -15,6 +15,7 @@ import cnames from "classnames"; import utils from "common/utils"; import LoadingIndicator from "../LoadingIndicator"; import ls from "common/localStorage"; +import PaginatedList from "../Utility/PaginatedList"; let accountStorage = new ls("__graphene__"); @@ -339,6 +340,27 @@ class Assets extends React.Component { .toArray(); } + let assetListHeader = ( + + + + + + + + + + + + + ); + return (
    @@ -404,34 +426,10 @@ class Assets extends React.Component { className="grid-block" style={{paddingBottom: 20}} > -
    - - - - - - - - - {mia} -
    - - - - - - -
    -
    +
    ) : null} @@ -457,35 +455,10 @@ class Assets extends React.Component { className="grid-block" style={{paddingBottom: 20}} > -
    - - - - - - - - - - {uia} -
    - - - - - - -
    -
    +
    ) : null} @@ -513,11 +486,7 @@ class Assets extends React.Component { className="grid-block" style={{paddingBottom: 20}} > -
    - - {pm} -
    -
    +
    ) : null}
    diff --git a/app/components/Utility/PaginatedList.jsx b/app/components/Utility/PaginatedList.jsx new file mode 100644 index 0000000000..816a7d596c --- /dev/null +++ b/app/components/Utility/PaginatedList.jsx @@ -0,0 +1,91 @@ +import React from "react"; +import {Pagination} from "antd"; +import counterpart from "counterpart"; +import TransitionWrapper from "../Utility/TransitionWrapper"; + +export default class PaginatedList extends React.Component { + constructor(props) { + super(props); + + this.state = { + page: 1, + pageSize: props.pageSize + }; + } + + static defaultProps = { + rows: [], + pageSize: 15, + label: "utility.total_x_items", + className: "table", + extraRow: null + }; + + onChange(page, pageSize) { + this.setState({page, pageSize}); + } + + render() { + const {page, pageSize} = this.state; + const {header, rows, extraRow} = this.props; + const total = rows.length; + + let currentRows = getRows(page, pageSize); + + function getRows(page, pageSize) { + let r = []; + for ( + var i = (page - 1) * pageSize; + i < Math.min(total, page * pageSize); + i++ + ) { + r.push(rows[i]); + } + return r; + } + + /* Paginated too far or filtered out options without changing the page */ + if (!currentRows.length && total) { + currentRows = getRows(1, pageSize); + } + + return ( +
    + + {header ? {header} : null} + {this.props.withTransition && page === 1 ? ( + + {currentRows} + {extraRow} + + ) : ( + + {currentRows} + {extraRow} + + )} +
    + + {total > pageSize ? ( + + counterpart.translate(this.props.label, { + count: total + }) + } + pageSize={pageSize} + current={page} + onChange={this.onChange.bind(this)} + /> + ) : null} + + {this.props.children} +
    + ); + } +} From 9c2dcf53a219a8f49b92f5fe3e506dbf9045486d Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 14:57:48 +0200 Subject: [PATCH 48/69] Fix some minor pagination styling issues --- app/components/Account/AccountPortfolioList.jsx | 2 ++ app/components/Utility/PaginatedList.jsx | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/components/Account/AccountPortfolioList.jsx b/app/components/Account/AccountPortfolioList.jsx index 536fc73ebf..425b2a52d4 100644 --- a/app/components/Account/AccountPortfolioList.jsx +++ b/app/components/Account/AccountPortfolioList.jsx @@ -888,6 +888,7 @@ class AccountPortfolioList extends React.Component { return (
    {this._renderSendModal()} {this._renderSettleModal()} diff --git a/app/components/Utility/PaginatedList.jsx b/app/components/Utility/PaginatedList.jsx index 816a7d596c..b662ba8abf 100644 --- a/app/components/Utility/PaginatedList.jsx +++ b/app/components/Utility/PaginatedList.jsx @@ -18,7 +18,8 @@ export default class PaginatedList extends React.Component { pageSize: 15, label: "utility.total_x_items", className: "table", - extraRow: null + extraRow: null, + style: {paddingBottom: "1rem"} }; onChange(page, pageSize) { @@ -50,7 +51,7 @@ export default class PaginatedList extends React.Component { } return ( -
    +
    {header ? {header} : null} {this.props.withTransition && page === 1 ? ( @@ -71,7 +72,11 @@ export default class PaginatedList extends React.Component { {total > pageSize ? ( counterpart.translate(this.props.label, { From 3d142f2ce6b4c96461629228954c793d7939077c Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 16:29:48 +0200 Subject: [PATCH 49/69] Fix #1744: Make sure BindToChainState compares null values correctly --- app/components/Utility/BindToChainState.jsx | 26 +++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/app/components/Utility/BindToChainState.jsx b/app/components/Utility/BindToChainState.jsx index d9ec16b885..bcc2e2c59a 100644 --- a/app/components/Utility/BindToChainState.jsx +++ b/app/components/Utility/BindToChainState.jsx @@ -347,6 +347,7 @@ function BindToChainState(Component, options = {}) { new_obj === null ) new_state[key] = new_obj; + ++all_objects_counter; if (new_obj !== undefined) ++resolved_objects_counter; } else { @@ -489,8 +490,29 @@ function BindToChainState(Component, options = {}) { new_state.resolved = true; let stateChanged = false; - for (let key in new_state) { - if (!utils.are_equal_shallow(new_state[key], this.state[key])) { + + /* + * are_equal_shallow won't correctly compare null to undefined, so + * we need to work around it by assigning a non-falsy value instead + * of null before making the comparison + */ + function replaceNull(state) { + let temp = {}; + for (let key in state) { + if (state[key] === null) temp[key] = "null"; + else temp[key] = state[key]; + } + return temp; + } + let temp_state = replaceNull(this.state); + let temp_new_state = replaceNull(new_state); + for (let key in temp_new_state) { + if ( + !utils.are_equal_shallow( + temp_new_state[key], + temp_state[key] + ) + ) { stateChanged = true; } else { delete new_state[key]; From b5c0b353c0133c483ec8a61040fc913e1a7328eb Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 16:32:00 +0200 Subject: [PATCH 50/69] Fix a bug causing infinite loading in Assets search page --- app/components/Explorer/Assets.jsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/app/components/Explorer/Assets.jsx b/app/components/Explorer/Assets.jsx index 12566de46b..2a523b125d 100644 --- a/app/components/Explorer/Assets.jsx +++ b/app/components/Explorer/Assets.jsx @@ -16,20 +16,29 @@ import utils from "common/utils"; import LoadingIndicator from "../LoadingIndicator"; import ls from "common/localStorage"; import PaginatedList from "../Utility/PaginatedList"; +import {Apis} from "bitsharesjs-ws"; let accountStorage = new ls("__graphene__"); class Assets extends React.Component { constructor(props) { super(); + + let chainID = Apis.instance().chain_id; + if (chainID) chainID = chainID.substr(0, 8); + else chainID = "4018d784"; + this.state = { + chainID, foundLast: false, lastAsset: "", isLoading: false, totalAssets: - typeof accountStorage.get("totalAssets") != "object" - ? accountStorage.get("totalAssets") - : 3000, + typeof accountStorage.get(`totalAssets_${chainID}`) != "object" + ? accountStorage.get(`totalAssets_${chainID}`) + : chainID && chainID === "4018d784" + ? 3000 + : 50, // mainnet has 3000+ assets, other chains may not have that many assetsFetched: 0, activeFilter: "market", filterUIA: props.filterUIA || "", @@ -72,7 +81,10 @@ class Assets extends React.Component { } if (assets.size > this.state.totalAssets) { - accountStorage.set("totalAssets", assets.size); + accountStorage.set( + `totalAssets_${this.state.chainID}`, + assets.size + ); } if (this.state.assetsFetched >= this.state.totalAssets - 100) { From 87fcae84bfc15e23c30bf0aa38fe1fde6eb82301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Wed, 1 Aug 2018 16:51:26 +0200 Subject: [PATCH 51/69] #1521: More node updates (#1743) * for #1521 filled in more apiConfig details Signed-off-by: Stefan Schiessl * update more nodes Signed-off-by: Stefan Schiessl * more nodes Signed-off-by: Stefan Schiessl * add more nodes Signed-off-by: Stefan Schiessl * Signed-off-by: Stefan Schiessl --- app/api/apiConfig.js | 116 ++++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 28 deletions(-) diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index 45bc4a2073..453e6cd8dc 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -113,19 +113,15 @@ export const settingsAPIs = { location: "Nuremberg", region: "Western Europe", country: "Germany", - operator: "Witness: openledger-dc" - }, - { - url: "wss://eu.openledger.info/ws", - location: "Berlin", - region: "Western Europe", - country: "Germany", - operator: "Witness: openledger-dc" + operator: "Witness: openledger-dc", + contact: "telegram:mtopenledger" }, { url: "wss://openledger.hk/ws", - location: "Hong Kong", - operator: "Witness: openledger-dc" + region: "Southeastern Asia", + country: "Singapore", + operator: "Witness: openledger-dc", + contact: "telegram:mtopenledger" }, { url: "wss://bitshares.nu/ws", @@ -139,7 +135,13 @@ export const settingsAPIs = { operator: "Witness: abc123" }, {url: "wss://node.btscharts.com/ws", location: "Hong Kong"}, - {url: "wss://japan.bitshares.apasia.tech/ws", location: "Tokyo, Japan"}, + { + url: "wss://japan.bitshares.apasia.tech/ws", + country: "Japan", + region: "Southeastern Asia", + operator: "APAsia", + contact: "telegram:murda_ra" + }, { url: "wss://bitshares.crypto.fans/ws", region: "Western Europe", @@ -174,13 +176,40 @@ export const settingsAPIs = { }, { url: "wss://kc-us-dex.xeldal.com/ws", - location: "Kansas City, USA", - operator: "Witness: Xeldal" + region: "North America", + country: "USA", + location: "Kansas City", + operator: "Witness: xeldal", + contact: "telegram:xeldal" }, {url: "wss://btsza.co.za:8091/ws", location: "Cape Town, South Africa"}, - {url: "wss://api.bts.blckchnd.com", location: "Falkenstein, Germany"}, - {url: "wss://api-ru.bts.blckchnd.com", location: "Moscow, Russia"}, - {url: "wss://node.market.rudex.org", location: "Germany"}, + { + url: "wss://api.bts.blckchnd.com", + region: "Western Europe", + country: "Germany", + location: "Falkenstein", + operator: "Witness: blckchnd", + contact: + "email:admin@blckchnd.com;telegram:ruslansalikhov;github:blckchnd" + }, + { + url: "wss://api-ru.bts.blckchnd.com", + region: "Eastern Europe", + country: "Russia", + location: "Moscow", + operator: "Witness: blckchnd", + contact: + "email:admin@blckchnd.com;telegram:ruslansalikhov;github:blckchnd" + }, + { + url: "wss://node.market.rudex.org", + region: "Western Europe", + country: "Germany", + location: "Falkenstein", + operator: "Witness: blckchnd", + contact: + "email:admin@blckchnd.com;telegram:ruslansalikhov;github:blckchnd" + }, { url: "wss://api.bitsharesdex.com", region: "Northern America", @@ -198,9 +227,12 @@ export const settingsAPIs = { contact: "telegram:ihashfury" }, { - url: "wss://blockzms.xyz/ws", - location: "USA", - operator: "Witness: delegate-zhaomu" + url: "wss://blockzms.xyz/ws ", + region: "North America", + country: "America", + location: "New Jersey", + operator: "Witness: delegate-zhaomu", + contact: "telegram:lzmlam;wechat:lzmlam" }, { url: "wss://eu.nodes.bitshares.ws", @@ -213,18 +245,22 @@ export const settingsAPIs = { url: "wss://us.nodes.bitshares.ws", region: "North America", country: "U.S.A.", - operator: "Infrastructure Worker" + operator: "Infrastructure Worker", + contact: "email:info@blockchainprojectsbv.com" }, { url: "wss://sg.nodes.bitshares.ws", region: "Southeastern Asia", country: "Singapore", - operator: "Infrastructure Worker" + operator: "Infrastructure Worker", + contact: "email:info@blockchainprojectsbv.com" }, { url: "wss://ws.winex.pro", + region: "Southeastern Asia", location: "Singapore", - operator: "Witness: winex.witness" + operator: "Witness: winex.witness", + contact: "telegram: zmaxin" }, { url: "wss://api.bts.mobi/ws", @@ -242,8 +278,10 @@ export const settingsAPIs = { }, { url: "wss://api.bts.network", - location: "East Coast, USA", - operator: "Witness: fox" + country: "U.S.A.", + region: "Northern America", + operator: "Witness: fox", + contact: "telegram:ryanRfox" }, { url: "wss://btsws.roelandp.nl/ws", @@ -296,13 +334,19 @@ export const settingsAPIs = { }, { url: "wss://freedom.bts123.cc:15138/", - location: "China", - operator: "Witness: delegate.freedom" + region: "South China", + country: "China", + location: "Changsha", + operator: "Witness: delegate.freedom", + contact: "telegram:eggplant" }, { url: "wss://bitshares.bts123.cc:15138/", - location: "China", - operator: "Witness: delegate.freedom" + region: "North China", + country: "China", + location: "Hangzhou", + operator: "Witness: delegate.freedom", + contact: "telegram:eggplant" }, { url: "wss://api.bts.ai/", @@ -339,6 +383,14 @@ export const settingsAPIs = { operator: "Witness: Bangzi", contact: "telegram:Bangzi" }, + { + url: "wss://api.dex.trading/", + region: "Western Europe", + country: "France", + location: "Paris", + operator: "Witness: zapata42-witness", + contact: "telegram:Zapata_42" + }, // Testnet { url: "wss://node.testnet.bitshares.eu", @@ -351,6 +403,14 @@ export const settingsAPIs = { { url: "wss://testnet.bitshares.apasia.tech/ws", location: "TESTNET - APT BitShares (Dallas, USA)" + }, + { + url: "wss://testnet.dex.trading/", + region: "Western Europe", + country: "France", + location: "Paris", + operator: "Witness: zapata42-witness", + contact: "telegram:Zapata_42" } ], DEFAULT_FAUCET: getFaucet().url, From c32090d92192b036ff0ff316416ff3480763e799 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 16:57:48 +0200 Subject: [PATCH 52/69] Update version and changelog for 180808-rc1 --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19c9c5ca74..9adddd8fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,40 @@ +--------------------------------------------------------------------- +Release 2.0.180808-rc1 +--------------------------------------------------------------------- +New features +-------- +- #1740: Add pagination to several tables +- #1576: Add target collateral ratio to orderbook calculations +- #1131: Add feed price publishing to Asset page +- #1629: Move burn asset to portfolio, fee claiming to Asset page +- #1596: Add new asset_update_issuer operation +- #1598: Add fee pool claim and cleanup Asset page +- #1550: Make preferred units depend on the network (main/testnet) +- #1521, #1672, #1462: Better Node Management +- #1575: Adding UI for Target CR on Modal +- #1701: Implement an advanced ping strategy + +Bug fixes and improvements +-------- +- #1521: More node updates +- Fix a bug causing infinite loading in Assets search page +- Fix #1744: Make sure BindToChainState compares null values correctly +- #1521: Update API node details +- #1131: Use ratio instead of percent for mcr and mssr +- #1596: Move Asset fee claiming to Asset page actions tab +- #1706: Update scam accounts list +- Fix #1723: Clean up proxy input field, add tooltips +- #1712: Add OPEN.EOSDAC asset to default lists +- #1712: Improve find market search results +- Fix #1727: Target CR Delimiter +- Fix #1628: Add checker for inputs on withdrawal +- Fix #1688 - Add Trading link to margin table +- Fix #1667 - Dashboard Column Reordering +- Fix #1704: Theme Issues on Asset Explorer +- #1575: Fixes for Target CR +- #1672: Remove API nodes without support for orders API +- Update russian translations (#1709) + --------------------------------------------------------------------- Release 2.0.180720 --------------------------------------------------------------------- diff --git a/package.json b/package.json index c6b66895a9..69ea3e26c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "BitShares2-light", - "version": "2.0.180720", + "version": "2.0.180808-rc1", "description": "Advanced wallet interface for the BitShares financial blockchain.", "homepage": "https://github.com/bitshares/bitshares-ui", "author": "Sigve Kvalsvik ", From 3f07742cf25b393d440351358f4c7cc964a7a581 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 1 Aug 2018 17:01:20 +0200 Subject: [PATCH 53/69] Update package-lock --- package-lock.json | 184 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 172 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1763146740..299c74f547 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "BitShares2-light", - "version": "2.0.180720", + "version": "2.0.180808-rc1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4118,6 +4118,13 @@ "array-find-index": "^1.0.1" } }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true, + "optional": true + }, "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", @@ -5709,6 +5716,13 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true, + "optional": true + }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", @@ -9432,6 +9446,17 @@ "minimalistic-assert": "^1.0.0" } }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, + "optional": true, + "requires": { + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" + } + }, "hawk": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", @@ -11916,27 +11941,24 @@ "dev": true }, "jshint": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", - "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz", + "integrity": "sha512-KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", - "lodash": "3.7.x", + "lodash": "~4.17.10", "minimatch": "~3.0.2", + "phantom": "~4.0.1", + "phantomjs-prebuilt": "~2.1.7", "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" + "strip-json-comments": "1.0.x", + "unicode-5.2.0": "^0.7.5" }, "dependencies": { - "lodash": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", - "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", - "dev": true - }, "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", @@ -12041,6 +12063,13 @@ "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", "dev": true }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true, + "optional": true + }, "keyv": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", @@ -14256,6 +14285,64 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "phantom": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz", + "integrity": "sha512-Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==", + "dev": true, + "optional": true, + "requires": { + "phantomjs-prebuilt": "^2.1.16", + "split": "^1.0.1", + "winston": "^2.4.0" + } + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "dev": true, + "optional": true, + "requires": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true, + "optional": true + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true, + "optional": true + } + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -17038,6 +17125,25 @@ "uuid": "^3.1.0" } }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, + "optional": true, + "requires": { + "throttleit": "^1.0.0" + }, + "dependencies": { + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true, + "optional": true + } + } + }, "request-promise-core": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", @@ -18208,6 +18314,16 @@ "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=", "dev": true }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "optional": true, + "requires": { + "through": "2" + } + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -18252,6 +18368,13 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "optional": true + }, "stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", @@ -19156,6 +19279,12 @@ "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", "dev": true }, + "unicode-5.2.0": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz", + "integrity": "sha512-KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==", + "dev": true + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -20890,6 +21019,37 @@ "dev": true, "optional": true }, + "winston": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.3.tgz", + "integrity": "sha512-GYKuysPz2pxYAVJD2NPsDLP5Z79SDEzPm9/j4tCjkF/n89iBNGBMJcR+dMUqxgPNgoSs6fVygPi+Vl2oxIpBuw==", + "dev": true, + "optional": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true, + "optional": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "optional": true + } + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", From 4f823b7bc2d2b3a5cd57c9ba39a94290bacfee85 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Thu, 2 Aug 2018 14:36:21 +0200 Subject: [PATCH 54/69] Fix #1745: are_equal_shallow bug --- app/components/Exchange/QuoteSelectionModal.jsx | 5 ----- app/lib/common/utils.js | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/components/Exchange/QuoteSelectionModal.jsx b/app/components/Exchange/QuoteSelectionModal.jsx index 0e8ad587a0..68b531575e 100644 --- a/app/components/Exchange/QuoteSelectionModal.jsx +++ b/app/components/Exchange/QuoteSelectionModal.jsx @@ -59,11 +59,6 @@ export default class QuoteSelectionModal extends React.Component { _onFoundBackingAsset(asset) { if (asset) { - console.log( - "asset", - asset.get("symbol"), - this.props.quotes.includes(asset.get("symbol")) - ); if (!this.props.quotes.includes(asset.get("symbol"))) { this.setState({isValid: true}); } else { diff --git a/app/lib/common/utils.js b/app/lib/common/utils.js index 0e61d2791d..0837fd84de 100644 --- a/app/lib/common/utils.js +++ b/app/lib/common/utils.js @@ -231,7 +231,13 @@ var Utils = { } if (typeof a === "string" && typeof b === "string") { return a === b; + } else if ( + (typeof a === "string" && typeof b !== "string") || + (typeof a !== "string" && typeof b === "string") + ) { + return false; } + if (a && a.toJS && b && b.toJS) return a === b; for (var key in a) { if ((a.hasOwnProperty(key) && !(key in b)) || a[key] !== b[key]) { From 052186a67b5474d5f8683a054ca80cbcc3a22d16 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Fri, 3 Aug 2018 10:45:57 +0200 Subject: [PATCH 55/69] Fix #1737: Make sure groupedOrder selection is used when switching chart timeframes --- app/actions/MarketsActions.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/actions/MarketsActions.js b/app/actions/MarketsActions.js index fabbbc26f2..7ec3070a30 100644 --- a/app/actions/MarketsActions.js +++ b/app/actions/MarketsActions.js @@ -35,6 +35,7 @@ const marketStatsQueueLength = 500; // Number of get_ticker calls per batch const marketStatsQueueTimeout = 1.5; // Seconds before triggering a queue processing let marketStatsQueueActive = false; +let currentGroupedOrderLimit = 0; class MarketsActions { changeBase(market) { clearBatchTimeouts(); @@ -127,6 +128,15 @@ class MarketsActions { } subscribeMarket(base, quote, bucketSize, groupedOrderLimit) { + /* + * DataFeed will call subscribeMarket with undefined groupedOrderLimit, + * so we keep track of the last value used and use that instead in that + * case + */ + if (typeof groupedOrderLimit === "undefined") + groupedOrderLimit = currentGroupedOrderLimit; + else currentGroupedOrderLimit = groupedOrderLimit; + clearBatchTimeouts(); let subID = quote.get("id") + "_" + base.get("id"); currentMarket = base.get("id") + "_" + quote.get("id"); From a60491c8eb60fc6d6af570457d4dfebaaf353760 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Fri, 3 Aug 2018 16:19:43 +0200 Subject: [PATCH 56/69] Fix #1752: Account with no balances crashes the GUI --- app/components/Modal/ReserveAssetModal.jsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/components/Modal/ReserveAssetModal.jsx b/app/components/Modal/ReserveAssetModal.jsx index 67843c94e5..8aa5cd63a2 100644 --- a/app/components/Modal/ReserveAssetModal.jsx +++ b/app/components/Modal/ReserveAssetModal.jsx @@ -20,7 +20,6 @@ class ReserveAssetModal extends React.Component { this.props.asset && np.asset.get("id") !== this.props.asset.get("id") ) { - console.log("new asset:", np.asset.get("id")); this.setState(this.getInitialState(np)); } } @@ -56,9 +55,13 @@ class ReserveAssetModal extends React.Component { render() { let assetId = this.props.asset.get("id"); - let currentBalance = ChainStore.getObject( - this.props.account.getIn(["balances", assetId]) - ); + let currentBalance = + this.props.account && this.props.account.get("balances", []).size + ? ChainStore.getObject( + this.props.account.getIn(["balances", assetId]) + ) + : null; + if (!currentBalance) return null; return ( From 172444860315fc767d28d5e204441e625604df3d Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Thu, 2 Aug 2018 14:54:28 +0200 Subject: [PATCH 57/69] Fix #1748: Disable release notifications in RC builds --- app/components/Layout/Footer.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/components/Layout/Footer.jsx b/app/components/Layout/Footer.jsx index 1ca8486c9f..ba04e35fcf 100644 --- a/app/components/Layout/Footer.jsx +++ b/app/components/Layout/Footer.jsx @@ -80,7 +80,9 @@ class Footer extends React.Component { function(json) { let oldVersion = String(json.tag_name); let newVersion = String(APP_VERSION); - if (oldVersion !== newVersion) { + let isReleaseCandidate = + APP_VERSION.indexOf("rc") !== -1; + if (!isReleaseCandidate && oldVersion !== newVersion) { this.setState({newVersion}); } }.bind(this) @@ -322,6 +324,8 @@ class Footer extends React.Component { let version = version_match ? `.${version_match[1]}` : ` ${APP_VERSION}`; + let rc_match = APP_VERSION.match(/-rc[0-9]$/); + if (rc_match) version += rc_match[0]; let updateStyles = {display: "inline-block", verticalAlign: "top"}; let logoProps = {}; From bb3872a085b6542f0c1096fc9b58067209c09893 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Fri, 3 Aug 2018 16:42:10 +0200 Subject: [PATCH 58/69] Update changelog and version for 180808-rc2 --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9adddd8fcb..295eba1334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +--------------------------------------------------------------------- +Release 2.0.180808-rc2 +--------------------------------------------------------------------- +Bug fixes and improvements +-------- +- Fix #1752: Account with no balances crashes the GUI +- Fix #1748: Disable release notifications in RC builds +- Fix #1745: are_equal_shallow bug +- Fix #1737: Make sure groupedOrder selection is used when switching chart timeframes + --------------------------------------------------------------------- Release 2.0.180808-rc1 --------------------------------------------------------------------- diff --git a/package.json b/package.json index 69ea3e26c3..cd7a7ee3a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "BitShares2-light", - "version": "2.0.180808-rc1", + "version": "2.0.180808-rc2", "description": "Advanced wallet interface for the BitShares financial blockchain.", "homepage": "https://github.com/bitshares/bitshares-ui", "author": "Sigve Kvalsvik ", From f5702507437935206393563391720473a61fedff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Fri, 3 Aug 2018 17:09:38 +0200 Subject: [PATCH 59/69] #1521: Update nodes (#1754) * for #1521 filled in more apiConfig details Signed-off-by: Stefan Schiessl * update more nodes Signed-off-by: Stefan Schiessl * more nodes Signed-off-by: Stefan Schiessl * add more nodes Signed-off-by: Stefan Schiessl * Signed-off-by: Stefan Schiessl * some more nodes Signed-off-by: Stefan Schiessl --- app/api/apiConfig.js | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index 453e6cd8dc..fe6083c715 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -131,8 +131,11 @@ export const settingsAPIs = { }, { url: "wss://bit.btsabc.org/ws", + region: "Eastern Asia", + country: "China", location: "Hong Kong", - operator: "Witness: abc123" + operator: "Witness: abc123", + contact: "QQ:58291;email:58291@qq.com" }, {url: "wss://node.btscharts.com/ws", location: "Hong Kong"}, { @@ -229,7 +232,7 @@ export const settingsAPIs = { { url: "wss://blockzms.xyz/ws ", region: "North America", - country: "America", + country: "U.S.A.", location: "New Jersey", operator: "Witness: delegate-zhaomu", contact: "telegram:lzmlam;wechat:lzmlam" @@ -277,9 +280,10 @@ export const settingsAPIs = { operator: "Witness: elmato" }, { - url: "wss://api.bts.network", - country: "U.S.A.", - region: "Northern America", + url: "wss://api.bts.network/", + region: "North America", + country: "USA", + location: "Virginia", operator: "Witness: fox", contact: "telegram:ryanRfox" }, @@ -293,8 +297,10 @@ export const settingsAPIs = { }, { url: "wss://api.bitshares.bhuz.info/ws", - location: "Europe", - operator: "Witness: bhuz" + region: "Northern America", + country: "Canada", + operator: "Witness: bhuz", + contact: "telegram: bhuzor" }, { url: "wss://bts-api.lafona.net/ws", @@ -311,8 +317,10 @@ export const settingsAPIs = { }, { url: "wss://api.btsgo.net/ws", + region: "Asia", location: "Singapore", - operator: "Witness: xn-delegate" + operator: "Witness: xn-delegate", + contact: "wechat:Necklace" }, { url: "wss://bts.proxyhosts.info/wss", @@ -329,8 +337,11 @@ export const settingsAPIs = { }, { url: "wss://crazybit.online", - location: "China", - operator: "Witness: crazybit" + region: "Asia", + country: "China", + location: "Shenzhen", + operator: "Witness: crazybit", + contact: "telegram:crazybits;wechat:JamesCai" }, { url: "wss://freedom.bts123.cc:15138/", @@ -355,9 +366,12 @@ export const settingsAPIs = { }, {url: "wss://ws.hellobts.com/", location: "Japan"}, { - url: "wss://bitshares.cyberit.io/", + url: "wss://bitshares.cyberit.io", + region: "Eastern Asia", + country: "China", location: "Hong Kong", - operator: "Witness: witness.still" + operator: "Witness: witness.still", + contact: "telegram:gordoor;wechat:overyard" }, { url: "wss://bts-seoul.clockwork.gr", From a34c1d830dd9b5adc9e591b718cfff5ed713d702 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Tue, 7 Aug 2018 12:02:03 +0200 Subject: [PATCH 60/69] Update webpack and some other packages --- app/components/Account/VotingAccountsList.jsx | 5 + app/components/Blockchain/Asset.jsx | 72 +- app/components/Blockchain/MemoText.jsx | 27 +- app/components/Explorer/CommitteeMembers.jsx | 39 +- app/components/Modal/QrcodeModal.jsx | 4 - app/components/News.jsx | 9 +- app/components/Utility/HelpContent.jsx | 15 +- app/lib/common/asset_utils.js | 9 +- package-lock.json | 23588 ++++++++-------- package.json | 4 +- webpack.config.js | 1 + 11 files changed, 11135 insertions(+), 12638 deletions(-) diff --git a/app/components/Account/VotingAccountsList.jsx b/app/components/Account/VotingAccountsList.jsx index 53e32bd8c9..7b9906bd86 100644 --- a/app/components/Account/VotingAccountsList.jsx +++ b/app/components/Account/VotingAccountsList.jsx @@ -9,6 +9,7 @@ import BindToChainState from "../Utility/BindToChainState"; import LinkToAccountById from "../Utility/LinkToAccountById"; import counterpart from "counterpart"; import PropTypes from "prop-types"; +import sanitize from "sanitize"; function getWitnessOrCommittee(type, acct) { let url = "", @@ -21,6 +22,10 @@ function getWitnessOrCommittee(type, acct) { } url = account ? account.get("url") : url; + url = sanitize(url, { + whiteList: [], // empty, means filter out all tags + stripIgnoreTag: true // filter out all HTML not in the whilelist + }); votes = account ? account.get("total_votes") : votes; return { url, diff --git a/app/components/Blockchain/Asset.jsx b/app/components/Blockchain/Asset.jsx index 75d96e74d9..84fb4485bf 100644 --- a/app/components/Blockchain/Asset.jsx +++ b/app/components/Blockchain/Asset.jsx @@ -279,7 +279,6 @@ class Asset extends React.Component { } let {name, prefix} = utils.replaceName(originalAsset); - return (

    - : -  {this.renderAuthorityList(options.blacklist_authorities)} + + :   + {this.renderAuthorityList(options.blacklist_authorities)}
    - : -  {this.renderMarketList(asset, options.blacklist_markets)} + + :   + {this.renderMarketList(asset, options.blacklist_markets)}
    - : -  {this.renderAuthorityList(options.whitelist_authorities)} + + :   + {this.renderAuthorityList(options.whitelist_authorities)}
    - : -  {this.renderMarketList(asset, options.whitelist_markets)} + + :   + {this.renderMarketList(asset, options.whitelist_markets)} ) : null; @@ -945,24 +948,26 @@ class Asset extends React.Component {
    @@ -1287,18 +1296,21 @@ class Asset extends React.Component { } } -Asset = connect(Asset, { - listenTo() { - return [AccountStore]; - }, - getProps() { - return { - currentAccount: - AccountStore.getState().currentAccount || - AccountStore.getState().passwordAccount - }; +Asset = connect( + Asset, + { + listenTo() { + return [AccountStore]; + }, + getProps() { + return { + currentAccount: + AccountStore.getState().currentAccount || + AccountStore.getState().passwordAccount + }; + } } -}); +); Asset = AssetWrapper(Asset, { propNames: ["backingAsset"] diff --git a/app/components/Blockchain/MemoText.jsx b/app/components/Blockchain/MemoText.jsx index eeaf2a67f1..54828fecc6 100644 --- a/app/components/Blockchain/MemoText.jsx +++ b/app/components/Blockchain/MemoText.jsx @@ -20,11 +20,14 @@ class MemoText extends React.Component { ); } + componentDidMount() { + ReactTooltip.rebuild(); + } + _toggleLock(e) { e.preventDefault(); WalletUnlockActions.unlock() .then(() => { - console.log("unlocked"); ReactTooltip.rebuild(); }) .catch(() => {}); @@ -65,7 +68,6 @@ class MemoText extends React.Component { data-tip={full_memo !== text ? full_memo : null} data-place="bottom" data-offset="{'bottom': 10}" - data-html > {text} @@ -83,13 +85,16 @@ class MemoTextStoreWrapper extends React.Component { } } -export default connect(MemoTextStoreWrapper, { - listenTo() { - return [WalletUnlockStore]; - }, - getProps() { - return { - wallet_locked: WalletUnlockStore.getState().locked - }; +export default connect( + MemoTextStoreWrapper, + { + listenTo() { + return [WalletUnlockStore]; + }, + getProps() { + return { + wallet_locked: WalletUnlockStore.getState().locked + }; + } } -}); +); diff --git a/app/components/Explorer/CommitteeMembers.jsx b/app/components/Explorer/CommitteeMembers.jsx index aa4436e6ce..47654efe96 100644 --- a/app/components/Explorer/CommitteeMembers.jsx +++ b/app/components/Explorer/CommitteeMembers.jsx @@ -10,6 +10,7 @@ import {connect} from "alt-react"; import SettingsActions from "actions/SettingsActions"; import SettingsStore from "stores/SettingsStore"; import {withRouter} from "react-router-dom"; +import sanitize from "sanitize"; class CommitteeMemberCard extends React.Component { static propTypes = { @@ -91,6 +92,10 @@ class CommitteeMemberRow extends React.Component { if (!committee_member_data) return null; let url = committee_member_data.get("url"); + url = sanitize(url, { + whiteList: [], // empty, means filter out all tags + stripIgnoreTag: true // filter out all HTML not in the whilelist + }); url = url && url.length > 0 && url.indexOf("http") === -1 ? "http://" + url @@ -364,7 +369,8 @@ class CommitteeMembers extends React.Component {
    - :{" "} + + :{" "} { Object.keys( globalObject.active_committee_members @@ -424,20 +430,23 @@ class CommitteeMembersStoreWrapper extends React.Component { } } -CommitteeMembersStoreWrapper = connect(CommitteeMembersStoreWrapper, { - listenTo() { - return [SettingsStore]; - }, - getProps() { - return { - cardView: SettingsStore.getState().viewSettings.get( - "cardViewCommittee" - ), - filterCommitteeMember: SettingsStore.getState().viewSettings.get( - "filterCommitteeMember" - ) - }; +CommitteeMembersStoreWrapper = connect( + CommitteeMembersStoreWrapper, + { + listenTo() { + return [SettingsStore]; + }, + getProps() { + return { + cardView: SettingsStore.getState().viewSettings.get( + "cardViewCommittee" + ), + filterCommitteeMember: SettingsStore.getState().viewSettings.get( + "filterCommitteeMember" + ) + }; + } } -}); +); export default CommitteeMembersStoreWrapper; diff --git a/app/components/Modal/QrcodeModal.jsx b/app/components/Modal/QrcodeModal.jsx index e452e8cfd6..04b2862bc1 100644 --- a/app/components/Modal/QrcodeModal.jsx +++ b/app/components/Modal/QrcodeModal.jsx @@ -126,8 +126,6 @@ class QrcodeModal extends React.Component { {this.state.isShowQrcode == false ? (
    -
    +
    {worker.name}
    diff --git a/package.json b/package.json index c1d3984ee5..2f52bc31b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "BitShares2-light", - "version": "2.0.180808-rc2", + "version": "2.0.180808", "description": "Advanced wallet interface for the BitShares financial blockchain.", "homepage": "https://github.com/bitshares/bitshares-ui", "author": "Sigve Kvalsvik ", From 1d788d306fa8f8fab4d0961c0e37679140e7a925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schie=C3=9Fl?= Date: Wed, 8 Aug 2018 10:00:23 +0200 Subject: [PATCH 68/69] More node updates (#1766) * - add more nodes - askToReconnectAfterSeconds in footer increased to 10 seconds - remove duplicate doQuickLatencyUpdate - beSatisfiedWith is now a map according to AccessSettings display - remove bug that you dont connect to your selected one if not autoselction Signed-off-by: Stefan Schiessl * consistent naming and testnet Signed-off-by: Stefan Schiessl * include 2 more nodes Signed-off-by: Stefan Schiessl --- app/api/apiConfig.js | 49 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/app/api/apiConfig.js b/app/api/apiConfig.js index 5ce2a5fd8f..d4915c48e6 100644 --- a/app/api/apiConfig.js +++ b/app/api/apiConfig.js @@ -123,6 +123,14 @@ export const settingsAPIs = { operator: "Witness: openledger-dc", contact: "telegram:mtopenledger" }, + { + url: "wss://na.openledger.info/ws", + location: "Quebec", + region: "Northern America", + country: "Canada", + operator: "Witness: openledger-dc", + contact: "telegram:mtopenledger" + }, { url: "wss://bitshares.nu/ws", location: "Stockholm", @@ -137,7 +145,14 @@ export const settingsAPIs = { operator: "Witness: abc123", contact: "QQ:58291;email:58291@qq.com" }, - {url: "wss://node.btscharts.com/ws", location: "Hong Kong"}, + { + url: "wss://node.btscharts.com/ws", + region: "Eastern Asia", + country: "China", + location: "Beijing", + operator: "leo2017", + contact: "wechat:wx8855221;email:8855221@qq.com" + }, { url: "wss://japan.bitshares.apasia.tech/ws", country: "Japan", @@ -169,7 +184,7 @@ export const settingsAPIs = { { url: "wss://la.dexnode.net/ws", region: "Northern America", - country: "USA", + country: "U.S.A.", location: "Los Angeles", operator: "Witness: Sahkan", contact: "telegram:Sahkan_bitshares" @@ -177,7 +192,7 @@ export const settingsAPIs = { { url: "wss://dexnode.net/ws", region: "Northern America", - country: "USA", + country: "U.S.A.", location: "Dallas", operator: "Witness: Sahkan", contact: "telegram:Sahkan_bitshares" @@ -185,7 +200,7 @@ export const settingsAPIs = { { url: "wss://kc-us-dex.xeldal.com/ws", region: "North America", - country: "USA", + country: "U.S.A.", location: "Kansas City", operator: "Witness: xeldal", contact: "telegram:xeldal" @@ -273,7 +288,7 @@ export const settingsAPIs = { { url: "wss://api.bts.mobi/ws", region: "Northern America", - country: "USA", + country: "U.S.A.", location: "Virginia", operator: "Witness: in.abit", contact: "telegram:abitmore" @@ -287,7 +302,7 @@ export const settingsAPIs = { { url: "wss://api.bts.network/", region: "North America", - country: "USA", + country: "U.S.A.", location: "Virginia", operator: "Witness: fox", contact: "telegram:ryanRfox" @@ -318,7 +333,7 @@ export const settingsAPIs = { { url: "wss://kimziv.com/ws", region: "North America", - country: "USA", + country: "U.S.A.", location: "New Jersey", operator: "Witness: witness.yao", contact: "telegram:imyao" @@ -426,19 +441,31 @@ export const settingsAPIs = { // Testnet { url: "wss://node.testnet.bitshares.eu", - location: "TESTNET - BitShares Europe (Frankfurt, Germany)" + region: "TESTNET - Western Europe", + country: "Germany", + location: "Frankfurt", + operator: "BitShares Europe", + contact: "telegram:xeroc" }, { url: "wss://testnet.nodes.bitshares.ws", - location: "TESTNET - BitShares Infrastructure Program" + region: "TESTNET - Western Europe", + country: "Germany", + location: "Nuremberg", + operator: "Infrastructure Worker", + contact: "email:info@blockchainprojectsbv.com" }, { url: "wss://testnet.bitshares.apasia.tech/ws", - location: "TESTNET - APT BitShares (Dallas, USA)" + region: "TESTNET - Northern America", + country: "U.S.A.", + location: "Dallas", + operator: "APAsia", + contact: "telegram:murda_ra" }, { url: "wss://testnet.dex.trading/", - region: "Western Europe", + region: "TESTNET - Western Europe", country: "France", location: "Paris", operator: "Witness: zapata42-witness", From a686562672cc17ef4ee2b3293a8fa003ed596c91 Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Wed, 8 Aug 2018 10:05:24 +0200 Subject: [PATCH 69/69] Update changelog --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 295eba1334..b6bf5643ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,46 @@ +--------------------------------------------------------------------- +Release 2.0.180808 +--------------------------------------------------------------------- +New features +-------- +- #1740: Add pagination to several tables +- #1576: Add target collateral ratio to orderbook calculations +- #1131: Add feed price publishing to Asset page +- #1629: Move burn asset to portfolio, fee claiming to Asset page +- #1596: Add new asset_update_issuer operation +- #1598: Add fee pool claim and cleanup Asset page +- #1550: Make preferred units depend on the network (main/testnet) +- #1521, #1672, #1462: Better Node Management +- #1575: Adding UI for Target CR on Modal +- #1701: Implement an advanced ping strategy + +Bug fixes and improvements +-------- +- #1521: Add more nodes and improve latency check +- Fix #1760 and AccountStoreBug (#1765) +- Fix #1752: Account with no balances crashes the GUI +- Fix #1748: Disable release notifications in RC builds +- Fix #1745: are_equal_shallow bug +- Fix #1737: Make sure groupedOrder selection is used when switching chart timeframes +- #1521: More node updates +- Fix a bug causing infinite loading in Assets search page +- Fix #1744: Make sure BindToChainState compares null values correctly +- #1521: Update API node details +- #1131: Use ratio instead of percent for mcr and mssr +- #1596: Move Asset fee claiming to Asset page actions tab +- #1706: Update scam accounts list +- Fix #1723: Clean up proxy input field, add tooltips +- #1712: Add OPEN.EOSDAC asset to default lists +- #1712: Improve find market search results +- Fix #1727: Target CR Delimiter +- Fix #1628: Add checker for inputs on withdrawal +- Fix #1688 - Add Trading link to margin table +- Fix #1667 - Dashboard Column Reordering +- Fix #1704: Theme Issues on Asset Explorer +- #1575: Fixes for Target CR +- #1672: Remove API nodes without support for orders API +- Update russian translations (#1709) + --------------------------------------------------------------------- Release 2.0.180808-rc2 ---------------------------------------------------------------------
    -
    - ({this.formattedPrice( +
    ( + {this.formattedPrice( settlement_price_header, false, true - )}) + )} + )
    -
    - ({this.formattedPrice( +
    ( + {this.formattedPrice( core_exchange_rate_header, false, true - )}) + )} + )
    @@ -1038,7 +1043,8 @@ class Asset extends React.Component { {this.state.callOrders.length ? ( -  ( {this.state.callOrders.length ? ( -  ( {this.state.callOrders.length ? ( -  () + /> + ) ) : null}