);
+ }
+
return (
{levels}
+ {error}
);
} else if (this.props.location.pathname !== "/edit") {
console.log("invalid path: " + this.props.location.pathname);
@@ -189,7 +189,7 @@ class NewBot extends Component {
configData={this.state.configData}
saveFn={this.saveEdit}
saveText="Save Bot Updates"
- error={this.state.error}
+ errorResp={this.state.errorResp}
/>);
}
}
From dcb47312c59b950fb403632c20db211ce82141f7 Mon Sep 17 00:00:00 2001
From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com>
Date: Thu, 11 Jul 2019 10:39:14 -0700
Subject: [PATCH 06/10] 6 - extract function validateConfigs
---
gui/backend/upsert_bot_config.go | 45 ++++++++++++++++++++++++++------
1 file changed, 37 insertions(+), 8 deletions(-)
diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go
index 320d1009c..9327f90c5 100644
--- a/gui/backend/upsert_bot_config.go
+++ b/gui/backend/upsert_bot_config.go
@@ -31,8 +31,8 @@ type upsertBotConfigResponseErrors struct {
Fields upsertBotConfigRequest `json:"fields"`
}
-func makeUpsertError(fields upsertBotConfigRequest) upsertBotConfigResponseErrors {
- return upsertBotConfigResponseErrors{
+func makeUpsertError(fields upsertBotConfigRequest) *upsertBotConfigResponseErrors {
+ return &upsertBotConfigResponseErrors{
Error: "There are some errors marked in red inline",
Fields: fields,
}
@@ -63,12 +63,8 @@ func (s *APIServer) upsertBotConfig(w http.ResponseWriter, r *http.Request) {
return
}
- if _, e = strkey.Decode(strkey.VersionByteSeed, req.TraderConfig.TradingSecretSeed); e != nil {
- s.writeJson(w, makeUpsertError(upsertBotConfigRequest{
- TraderConfig: trader.BotConfig{
- TradingSecretSeed: "invalid Trader Secret Key",
- },
- }))
+ if errResp := s.validateConfigs(req); errResp != nil {
+ s.writeJson(w, errResp)
return
}
@@ -93,3 +89,36 @@ func (s *APIServer) upsertBotConfig(w http.ResponseWriter, r *http.Request) {
s.writeJson(w, upsertBotConfigResponse{Success: true})
}
+
+func (s *APIServer) validateConfigs(req upsertBotConfigRequest) *upsertBotConfigResponseErrors {
+ hasError := false
+ errResp := upsertBotConfigRequest{
+ TraderConfig: trader.BotConfig{},
+ StrategyConfig: plugins.BuySellConfig{},
+ }
+
+ if _, e := strkey.Decode(strkey.VersionByteSeed, req.TraderConfig.TradingSecretSeed); e != nil {
+ errResp.TraderConfig.TradingSecretSeed = "invalid Trader Secret Key"
+ hasError = true
+ }
+
+ if req.TraderConfig.AssetCodeA == "" || len(req.TraderConfig.AssetCodeA) > 12 {
+ errResp.TraderConfig.AssetCodeA = "length must be between 0 - 12 characters"
+ hasError = true
+ }
+
+ if req.TraderConfig.AssetCodeB == "" || len(req.TraderConfig.AssetCodeB) > 12 {
+ errResp.TraderConfig.AssetCodeB = "length must be between 0 - 12 characters"
+ hasError = true
+ }
+
+ if _, e := strkey.Decode(strkey.VersionByteSeed, req.TraderConfig.SourceSecretSeed); req.TraderConfig.SourceSecretSeed != "" && e != nil {
+ errResp.TraderConfig.SourceSecretSeed = "invalid Source Secret Key"
+ hasError = true
+ }
+
+ if hasError {
+ return makeUpsertError(errResp)
+ }
+ return nil
+}
From 5252ac1fc53f0ee2a2737c859b88fe5d2e762197 Mon Sep 17 00:00:00 2001
From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com>
Date: Thu, 11 Jul 2019 10:41:39 -0700
Subject: [PATCH 07/10] 7 - dont display numerical errors if empty
---
gui/web/src/components/molecules/Form/Form.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gui/web/src/components/molecules/Form/Form.js b/gui/web/src/components/molecules/Form/Form.js
index 1cffa7098..bfeb6eae0 100644
--- a/gui/web/src/components/molecules/Form/Form.js
+++ b/gui/web/src/components/molecules/Form/Form.js
@@ -78,7 +78,7 @@ class Form extends Component {
for (let i = 0; i < parts.length; i++) {
obj = obj[parts[i]];
- if (obj === undefined || obj === null || obj === "") {
+ if (obj === undefined || obj === null || obj === "" || obj === 0) {
return null;
}
}
From cda15a843f5d2e810c076c0566aefe240c7032df Mon Sep 17 00:00:00 2001
From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com>
Date: Thu, 11 Jul 2019 10:59:21 -0700
Subject: [PATCH 08/10] 8 - add _positive type modifiers for the Input
component
---
gui/web/src/components/atoms/Input/Input.js | 28 ++++++++++++++--
gui/web/src/components/molecules/Form/Form.js | 32 +++++++++----------
.../src/components/molecules/Levels/Levels.js | 4 +--
3 files changed, 43 insertions(+), 21 deletions(-)
diff --git a/gui/web/src/components/atoms/Input/Input.js b/gui/web/src/components/atoms/Input/Input.js
index 22269674f..735db4138 100644
--- a/gui/web/src/components/atoms/Input/Input.js
+++ b/gui/web/src/components/atoms/Input/Input.js
@@ -41,10 +41,32 @@ class Input extends Component {
if (this.props.type === "int" || this.props.type === "float") {
// convert back to number so it is set correctly in the state
newEvent = { target: { value: +checked } };
+ } else if (this.props.type === "int_positive" || this.props.type === "float_positive") {
+ // ensure it is positive
+ let val = +checked
+ if (val === 0) {
+ // don't allow an update if it's zero
+ return
+ } else if (val < 0) {
+ val = -val
+ }
+ newEvent = { target: { value: val } };
} else if (this.props.type === "percent") {
// convert back to representation passed in to complete the abstraction of a % value input
// use event.target.value instead of checked here, because checked modified the value which is itself already modified
newEvent = { target: { value: +event.target.value / 100 } };
+ } else if (this.props.type === "percent_positive") {
+ // ensure it is positive
+ // use event.target.value instead of checked here, because checked modified the value which is itself already modified
+ let val = +event.target.value
+ if (val === 0) {
+ // don't allow an update if it's zero
+ return
+ } else if (val < 0) {
+ val = -val
+ }
+ // convert back to representation passed in to complete the abstraction of a % value input
+ newEvent = { target: { value: val / 100 } };
}
this.props.onChange(newEvent);
}
@@ -53,11 +75,11 @@ class Input extends Component {
checkType(input) {
if (this.props.type === "string") {
return this.isString(input);
- } else if (this.props.type === "int") {
+ } else if (this.props.type === "int" || this.props.type === "int_positive") {
return this.isInt(input);
- } else if (this.props.type === "float") {
+ } else if (this.props.type === "float" || this.props.type === "float_positive") {
return this.isFloat(input);
- } else if (this.props.type === "percent") {
+ } else if (this.props.type === "percent" || this.props.type === "percent_positive") {
return this.isPercent(input);
}
}
diff --git a/gui/web/src/components/molecules/Form/Form.js b/gui/web/src/components/molecules/Form/Form.js
index bfeb6eae0..6687e2085 100644
--- a/gui/web/src/components/molecules/Form/Form.js
+++ b/gui/web/src/components/molecules/Form/Form.js
@@ -404,7 +404,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.tick_interval_seconds", event) }}
error={this.getError("trader_config.tick_interval_seconds")}
/>
@@ -415,7 +415,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.max_tick_delay_millis", event) }}
error={this.getError("trader_config.max_tick_delay_millis")}
/>
@@ -440,7 +440,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.delete_cycles_threshold", event) }}
error={this.getError("trader_config.delete_cycles_threshold")}
/>
@@ -466,7 +466,7 @@ class Form extends Component {
{
@@ -491,7 +491,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.fill_tracker_delete_cycles_threshold", event) }}
error={this.getError("trader_config.fill_tracker_delete_cycles_threshold")}
@@ -505,7 +505,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.fee.capacity_trigger", event) }}
error={this.getError("trader_config.fee.capacity_trigger")}
/>
@@ -519,7 +519,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.fee.percentile", event) }}
error={this.getError("trader_config.fee.percentile")}
/>
@@ -533,7 +533,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.fee.max_op_fee_stroops", event) }}
error={this.getError("trader_config.fee.max_op_fee_stroops")}
/>
@@ -549,7 +549,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.centralized_price_precision_override", event) }}
error={this.getError("trader_config.centralized_price_precision_override")}
/>
@@ -561,7 +561,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.centralized_volume_precision_override", event) }}
error={this.getError("trader_config.centralized_volume_precision_override")}
/>
@@ -576,7 +576,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.centralized_min_base_volume_override", event) }}
error={this.getError("trader_config.centralized_min_base_volume_override")}
/>
@@ -588,7 +588,7 @@ class Form extends Component {
{ this.props.onChange("trader_config.centralized_min_quote_volume_override", event) }}
error={this.getError("trader_config.centralized_min_quote_volume_override")}
/>
@@ -670,7 +670,7 @@ class Form extends Component {
{ this.props.onChange("strategy_config.price_tolerance", event) }}
error={this.getError("strategy_config.price_tolerance")}
/>
@@ -682,7 +682,7 @@ class Form extends Component {
{ this.props.onChange("strategy_config.amount_tolerance", event) }}
error={this.getError("strategy_config.amount_tolerance")}
/>
@@ -697,7 +697,7 @@ class Form extends Component {
{ this.props.onChange("strategy_config.rate_offset_percent", event) }}
error={this.getError("strategy_config.rate_offset_percent")}
/>
@@ -708,7 +708,7 @@ class Form extends Component {
{ this.props.onChange("strategy_config.rate_offset", event) }}
error={this.getError("strategy_config.rate_offset")}
/>
diff --git a/gui/web/src/components/molecules/Levels/Levels.js b/gui/web/src/components/molecules/Levels/Levels.js
index a5735ac5d..8043f6d89 100644
--- a/gui/web/src/components/molecules/Levels/Levels.js
+++ b/gui/web/src/components/molecules/Levels/Levels.js
@@ -30,7 +30,7 @@ class Levels extends Component {
{ this.props.updateLevel(i, "spread", event.target.value) }}
/>
@@ -38,7 +38,7 @@ class Levels extends Component {
{ this.props.updateLevel(i, "amount", event.target.value) }}
/>
From c3908aeed1f620b987e4cd59579606ae74209757 Mon Sep 17 00:00:00 2001
From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com>
Date: Thu, 11 Jul 2019 11:01:59 -0700
Subject: [PATCH 09/10] 9 - better error message for asset codes
---
gui/backend/upsert_bot_config.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go
index 9327f90c5..bc8f93c4f 100644
--- a/gui/backend/upsert_bot_config.go
+++ b/gui/backend/upsert_bot_config.go
@@ -103,12 +103,12 @@ func (s *APIServer) validateConfigs(req upsertBotConfigRequest) *upsertBotConfig
}
if req.TraderConfig.AssetCodeA == "" || len(req.TraderConfig.AssetCodeA) > 12 {
- errResp.TraderConfig.AssetCodeA = "length must be between 0 - 12 characters"
+ errResp.TraderConfig.AssetCodeA = "1 - 12 characters"
hasError = true
}
if req.TraderConfig.AssetCodeB == "" || len(req.TraderConfig.AssetCodeB) > 12 {
- errResp.TraderConfig.AssetCodeB = "length must be between 0 - 12 characters"
+ errResp.TraderConfig.AssetCodeB = "1 - 12 characters"
hasError = true
}
From 777b62eaba933f09be0abed98fdb87b6d8f869c2 Mon Sep 17 00:00:00 2001
From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com>
Date: Thu, 11 Jul 2019 11:19:53 -0700
Subject: [PATCH 10/10] 10 - validation for levels, fix empty level values
---
gui/backend/upsert_bot_config.go | 14 ++++++++++++++
gui/web/src/components/molecules/Form/Form.js | 4 ++--
gui/web/src/components/molecules/Levels/Levels.js | 2 +-
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go
index bc8f93c4f..c042f8a0b 100644
--- a/gui/backend/upsert_bot_config.go
+++ b/gui/backend/upsert_bot_config.go
@@ -117,8 +117,22 @@ func (s *APIServer) validateConfigs(req upsertBotConfigRequest) *upsertBotConfig
hasError = true
}
+ if len(req.StrategyConfig.Levels) == 0 || hasNewLevel(req.StrategyConfig.Levels) {
+ errResp.StrategyConfig.Levels = []plugins.StaticLevel{}
+ hasError = true
+ }
+
if hasError {
return makeUpsertError(errResp)
}
return nil
}
+
+func hasNewLevel(levels []plugins.StaticLevel) bool {
+ for _, l := range levels {
+ if l.AMOUNT == 0 || l.SPREAD == 0 {
+ return true
+ }
+ }
+ return false
+}
diff --git a/gui/web/src/components/molecules/Form/Form.js b/gui/web/src/components/molecules/Form/Form.js
index 6687e2085..9317e53ee 100644
--- a/gui/web/src/components/molecules/Form/Form.js
+++ b/gui/web/src/components/molecules/Form/Form.js
@@ -166,8 +166,8 @@ class Form extends Component {
_emptyLevel() {
return {
- amount: "0.00",
- spread: "0.00",
+ amount: 0.00,
+ spread: 0.00,
};
}
diff --git a/gui/web/src/components/molecules/Levels/Levels.js b/gui/web/src/components/molecules/Levels/Levels.js
index 8043f6d89..b840df1be 100644
--- a/gui/web/src/components/molecules/Levels/Levels.js
+++ b/gui/web/src/components/molecules/Levels/Levels.js
@@ -58,7 +58,7 @@ class Levels extends Component {
let error = "";
if (this.props.error) {
- error = ();
+ error = ();
}
return (