From fe19dcbaac0845e5bec7415528ffe02db93245af Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Mon, 11 May 2020 16:35:36 +0530 Subject: [PATCH] fix issue of fiat currency dropdown not updating correctly (closes #418) (#419) * 1 - update selected value used in dropdown to match dropdown options by replacing with * 2 - simplify fiat API dropdown options and augment URL only on client side * 3 - allow queryPrice to succeed by using the original feed_url --- gui/backend/options_metadata.go | 2 +- gui/web/src/components/molecules/Form/Form.js | 59 +++++++++++++++---- .../PriceFeedAsset/PriceFeedAsset.js | 6 +- .../PriceFeedSelector/PriceFeedSelector.js | 8 +-- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/gui/backend/options_metadata.go b/gui/backend/options_metadata.go index f5f84ff69..3c2843452 100644 --- a/gui/backend/options_metadata.go +++ b/gui/backend/options_metadata.go @@ -114,7 +114,7 @@ func (dob *dropdownOptionsBuilder) coinmarketcap(tickerCode string, currencyName } func (dob *dropdownOptionsBuilder) currencylayer(tickerCode string, name string) *dropdownOptionsBuilder { - value := fmt.Sprintf("http://apilayer.net/api/live?access_key=¤cies=%s", tickerCode) + value := tickerCode text := fmt.Sprintf("%s - %s", tickerCode, name) return dob._leaf(value, text) } diff --git a/gui/web/src/components/molecules/Form/Form.js b/gui/web/src/components/molecules/Form/Form.js index 629c8e16a..712cdc4be 100644 --- a/gui/web/src/components/molecules/Form/Form.js +++ b/gui/web/src/components/molecules/Form/Form.js @@ -21,11 +21,11 @@ import PriceFeedFormula from '../PriceFeedFormula/PriceFeedFormula'; import Levels from '../Levels/Levels'; import ErrorMessage from '../ErrorMessage/ErrorMessage'; import newSecretKey from '../../../kelp-ops-api/newSecretKey'; +import fetchPrice from '../../../kelp-ops-api/fetchPrice'; import SecretKey from '../SecretKey/SecretKey'; const fiatURLPrefix = "http://apilayer.net/api/live?access_key="; const fiatURLCurrencyParam = "¤cies="; -const fiatAPIKeyPlaceholder = ""; const currencyLayerWebsite = "https://currencylayer.com/"; class Form extends Component { @@ -60,7 +60,9 @@ class Form extends Component { this.addLevelError = this.addLevelError.bind(this); this.clearLevelError = this.clearLevelError.bind(this); this.makeNewFiatDataFeedURL = this.makeNewFiatDataFeedURL.bind(this); + this.extractCurrencyCodeFromFiatURL = this.extractCurrencyCodeFromFiatURL.bind(this); this.updateFiatAPIKey = this.updateFiatAPIKey.bind(this); + this.getConfigFeedURLTransformIfFiat = this.getConfigFeedURLTransformIfFiat.bind(this); this._emptyLevel = this._emptyLevel.bind(this); this._triggerUpdateLevels = this._triggerUpdateLevels.bind(this); this._fetchDotNotation = this._fetchDotNotation.bind(this); @@ -69,6 +71,7 @@ class Form extends Component { this._asyncRequests = {}; } + // _extractFiatAPIKey gets called when we load the config and we want to populate the fiat APIKey in the GUI _extractFiatAPIKey(props) { let url = null; if (props.configData.strategy_config.data_type_a === "fiat") { @@ -89,6 +92,19 @@ class Form extends Component { return url.substring(fiatURLPrefix.length, url.indexOf(fiatURLCurrencyParam)); } + // getConfigFeedURLTransformIfFiat is called when loading the config value for feed URLs + // we want to load only the currencyCode + getConfigFeedURLTransformIfFiat(ab) { + let dataType = this.props.configData.strategy_config["data_type_" + ab] + let feedUrl = this.props.configData.strategy_config["data_feed_" + ab + "_url"]; + + if (dataType === "fiat") { + const currencyCode = this.extractCurrencyCodeFromFiatURL(feedUrl); + return currencyCode; + } + return feedUrl; + } + componentWillUnmount() { if (this._asyncRequests["secretKey"]) { delete this._asyncRequests["secretKey"]; @@ -200,9 +216,11 @@ class Form extends Component { feedUrlValue = feedUrlValue + "/" + newValues[2]; } - // special handling for fiat feeds + // when the users selects a new fiat feed currency, wrap the currencyCode (feedUrlValue) with the fiat URL format + // so it can be saved in the config file which requires a URL. + // This leaves the UI text in the dropdown unchanged if (dataTypeValue === "fiat") { - feedUrlValue = feedUrlValue.replace(fiatAPIKeyPlaceholder, this.state.fiatAPIKey); + feedUrlValue = this.makeNewFiatDataFeedURL(this.state.fiatAPIKey, feedUrlValue); } let mergeUpdateInstructions = {}; @@ -329,19 +347,24 @@ class Form extends Component { }); } - makeNewFiatDataFeedURL(apiKey, oldURL) { - return fiatURLPrefix + apiKey + oldURL.substring(oldURL.indexOf(fiatURLCurrencyParam)); + makeNewFiatDataFeedURL(apiKey, currencyCode) { + return fiatURLPrefix + apiKey + fiatURLCurrencyParam + currencyCode; + } + + extractCurrencyCodeFromFiatURL(url) { + return url.substring(url.indexOf(fiatURLCurrencyParam) + fiatURLCurrencyParam.length); } + // updateFiatAPIKey is called when the user upates the fiat API key in the GUI updateFiatAPIKey(apiKey) { if (this.props.configData.strategy_config.data_type_a === "fiat") { - const newValue = this.makeNewFiatDataFeedURL(apiKey, this.props.configData.strategy_config.data_feed_a_url); - this.props.onChange("strategy_config.data_feed_a_url", {target: {value: newValue }}); + const newValue = this.makeNewFiatDataFeedURL(apiKey, this.extractCurrencyCodeFromFiatURL(this.props.configData.strategy_config.data_feed_a_url)); + this.props.onChange("strategy_config.data_feed_a_url", { target: { value: newValue } }); } if (this.props.configData.strategy_config.data_type_b === "fiat") { - const newValue = this.makeNewFiatDataFeedURL(apiKey, this.props.configData.strategy_config.data_feed_b_url); - this.props.onChange("strategy_config.data_feed_b_url", {target: {value: newValue }}); + const newValue = this.makeNewFiatDataFeedURL(apiKey, this.extractCurrencyCodeFromFiatURL(this.props.configData.strategy_config.data_feed_b_url)); + this.props.onChange("strategy_config.data_feed_b_url", { target: { value: newValue } }); } this.setState({ @@ -863,12 +886,17 @@ class Form extends Component { this.priceFeedAssetChangeHandler("a", newValues)} title={"Numerator: current price of base asset (" + this.props.configData.trader_config.asset_code_a + ")"} optionsMetadata={this.props.optionsMetadata} type={this.props.configData.strategy_config.data_type_a} - feed_url={this.props.configData.strategy_config.data_feed_a_url} + feed_url={this.getConfigFeedURLTransformIfFiat("a")} + fetchPrice={fetchPrice.bind( + this, + this.props.baseUrl, + this.props.configData.strategy_config.data_type_a, + this.props.configData.strategy_config.data_feed_a_url, + )} onLoadingPrice={() => this.setLoadingFormula()} onNewPrice={(newPrice) => this.updateFormulaPrice("numerator", newPrice)} readOnly={this.props.readOnly} @@ -876,12 +904,17 @@ class Form extends Component { this.priceFeedAssetChangeHandler("b", newValues)} title={"Denominator: current price of quote asset (" + this.props.configData.trader_config.asset_code_b + ")"} optionsMetadata={this.props.optionsMetadata} type={this.props.configData.strategy_config.data_type_b} - feed_url={this.props.configData.strategy_config.data_feed_b_url} + feed_url={this.getConfigFeedURLTransformIfFiat("b")} + fetchPrice={fetchPrice.bind( + this, + this.props.baseUrl, + this.props.configData.strategy_config.data_type_b, + this.props.configData.strategy_config.data_feed_b_url, + )} onLoadingPrice={() => this.setLoadingFormula()} onNewPrice={(newPrice) => this.updateFormulaPrice("denominator", newPrice)} readOnly={this.props.readOnly} diff --git a/gui/web/src/components/molecules/PriceFeedAsset/PriceFeedAsset.js b/gui/web/src/components/molecules/PriceFeedAsset/PriceFeedAsset.js index c6f9236f1..96f64980d 100644 --- a/gui/web/src/components/molecules/PriceFeedAsset/PriceFeedAsset.js +++ b/gui/web/src/components/molecules/PriceFeedAsset/PriceFeedAsset.js @@ -4,7 +4,6 @@ import styles from './PriceFeedAsset.module.scss'; import Label from '../../atoms/Label/Label'; import PriceFeedDisplay from '../PriceFeedDisplay/PriceFeedDisplay'; import PriceFeedSelector from '../PriceFeedSelector/PriceFeedSelector'; -import fetchPrice from '../../../kelp-ops-api/fetchPrice'; import LoadingAnimation from '../../atoms/LoadingAnimation/LoadingAnimation'; class PriceFeedAsset extends Component { @@ -20,11 +19,11 @@ class PriceFeedAsset extends Component { } static propTypes = { - baseUrl: PropTypes.string, title: PropTypes.string, type: PropTypes.string, feed_url: PropTypes.string, onChange: PropTypes.func, + fetchPrice: PropTypes.func, onLoadingPrice: PropTypes.func, onNewPrice: PropTypes.func, optionsMetadata: PropTypes.object, @@ -37,7 +36,6 @@ class PriceFeedAsset extends Component { componentDidUpdate(prevProps) { if ( - prevProps.baseUrl !== this.props.baseUrl || prevProps.type !== this.props.type || prevProps.feed_url !== this.props.feed_url ) { @@ -54,7 +52,7 @@ class PriceFeedAsset extends Component { this.props.onLoadingPrice(); var _this = this; - let currentRequest = fetchPrice.bind(this, this.props.baseUrl, this.props.type, this.props.feed_url); + let currentRequest = this.props.fetchPrice.bind(this); // we need to set the cached request to the current request so we always track the latest request we want processed this._asyncRequests["price"] = currentRequest; setTimeout(() => { diff --git a/gui/web/src/components/molecules/PriceFeedSelector/PriceFeedSelector.js b/gui/web/src/components/molecules/PriceFeedSelector/PriceFeedSelector.js index 960407d64..1d42e0bcb 100644 --- a/gui/web/src/components/molecules/PriceFeedSelector/PriceFeedSelector.js +++ b/gui/web/src/components/molecules/PriceFeedSelector/PriceFeedSelector.js @@ -60,7 +60,7 @@ class PriceFeedSelector extends Component { } selectedOption = selectedOption.subtype; } - + valuesToUpdate.push(curValue); i++; } @@ -85,7 +85,7 @@ class PriceFeedSelector extends Component { type="string" onChange={(event) => this.changeHandler(idx, event)} readOnly={this.props.readOnly} - /> + /> ); } else if (metadata.type === "dropdown") { @@ -98,7 +98,7 @@ class PriceFeedSelector extends Component { selected={value} onChange={(event) => this.changeHandler(idx, event)} readOnly={this.props.readOnly} - /> + /> ); } @@ -124,7 +124,7 @@ class PriceFeedSelector extends Component { } secondComponent = this.renderComponentRecursive(idx + 1, selectedOption.subtype, innerValues); } - + return (
{firstComponent}