Skip to content

Commit

Permalink
Merge pull request #1241 from rainlanguage/2025-02-06-select-tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
hardyjosh authored Feb 12, 2025
2 parents 8a875fc + 887b204 commit a4da043
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 76 deletions.
22 changes: 21 additions & 1 deletion crates/js_api/src/gui/deposits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,29 @@ impl DotrainOrderGui {

let token = deposit.token.as_ref().unwrap();
if !self.deposits.contains_key(&token.key) {
return Err(GuiError::DepositNotSet(token.key.clone()));
return Err(GuiError::DepositNotSet(
token
.symbol
.clone()
.unwrap_or(token.label.clone().unwrap_or(token.key.clone())),
));
}
}
Ok(())
}

#[wasm_bindgen(js_name = "getMissingDeposits")]
pub fn get_missing_deposits(&self) -> Result<Vec<String>, GuiError> {
let deployment = self.get_current_deployment()?;
let mut missing_deposits = Vec::new();

for deposit in deployment.deposits.iter() {
if let Some(token) = &deposit.token {
if !self.deposits.contains_key(&token.key) {
missing_deposits.push(token.key.clone());
}
}
}
Ok(missing_deposits)
}
}
15 changes: 14 additions & 1 deletion crates/js_api/src/gui/field_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,22 @@ impl DotrainOrderGui {

for field in deployment.fields.iter() {
if !self.field_values.contains_key(&field.binding) {
return Err(GuiError::FieldValueNotSet(field.binding.clone()));
return Err(GuiError::FieldValueNotSet(field.name.clone()));
}
}
Ok(())
}

#[wasm_bindgen(js_name = "getMissingFieldValues")]
pub fn get_missing_field_values(&self) -> Result<Vec<String>, GuiError> {
let deployment = self.get_current_deployment()?;
let mut missing_field_values = Vec::new();

for field in deployment.fields.iter() {
if !self.field_values.contains_key(&field.binding) {
missing_field_values.push(field.name.clone());
}
}
Ok(missing_field_values)
}
}
4 changes: 2 additions & 2 deletions crates/js_api/src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ pub enum GuiError {
DeploymentNotFound(String),
#[error("Field binding not found: {0}")]
FieldBindingNotFound(String),
#[error("Field value not set: {0}")]
#[error("Missing field value: {0}")]
FieldValueNotSet(String),
#[error("Deposit token not found in gui config: {0}")]
DepositTokenNotFound(String),
#[error("Deposit not set: {0}")]
#[error("Missing deposit with token: {0}")]
DepositNotSet(String),
#[error("Orderbook not found")]
OrderbookNotFound,
Expand Down
25 changes: 17 additions & 8 deletions crates/js_api/src/gui/select_tokens.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
use super::*;
use rain_orderbook_app_settings::{
deployment::Deployment, network::Network, order::Order, token::Token,
deployment::Deployment, gui::GuiSelectTokens, network::Network, order::Order, token::Token,
};
use std::str::FromStr;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Tsify)]
pub struct SelectTokens(Vec<GuiSelectTokens>);
impl_all_wasm_traits!(SelectTokens);

#[wasm_bindgen]
impl DotrainOrderGui {
#[wasm_bindgen(js_name = "getSelectTokens")]
pub fn get_select_tokens(&self) -> Result<Vec<String>, GuiError> {
pub fn get_select_tokens(&self) -> Result<SelectTokens, GuiError> {
let select_tokens = Gui::parse_select_tokens(
self.dotrain_order.dotrain_yaml().documents,
&self.selected_deployment,
)?;
Ok(select_tokens.unwrap_or(vec![]))
Ok(SelectTokens(select_tokens.unwrap_or(vec![])))
}

#[wasm_bindgen(js_name = "isSelectTokenSet")]
Expand All @@ -28,9 +32,14 @@ impl DotrainOrderGui {
)?;

if let Some(select_tokens) = select_tokens {
for key in select_tokens {
if self.dotrain_order.orderbook_yaml().get_token(&key).is_err() {
return Err(GuiError::TokenMustBeSelected(key.clone()));
for select_token in select_tokens {
if self
.dotrain_order
.orderbook_yaml()
.get_token(&select_token.key)
.is_err()
{
return Err(GuiError::TokenMustBeSelected(select_token.key.clone()));
}
}
}
Expand All @@ -49,7 +58,7 @@ impl DotrainOrderGui {
&self.selected_deployment,
)?
.ok_or(GuiError::SelectTokensNotSet)?;
if !select_tokens.contains(&key) {
if !select_tokens.iter().any(|token| token.key == key) {
return Err(GuiError::TokenNotFound(key.clone()));
}

Expand Down Expand Up @@ -97,7 +106,7 @@ impl DotrainOrderGui {
&self.selected_deployment,
)?
.ok_or(GuiError::SelectTokensNotSet)?;
if !select_tokens.contains(&key) {
if !select_tokens.iter().any(|token| token.key == key) {
return Err(GuiError::TokenNotFound(key.clone()));
}

Expand Down
12 changes: 8 additions & 4 deletions crates/js_api/src/gui/state_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,13 @@ impl DotrainOrderGui {
self.dotrain_order.dotrain_yaml().documents.clone(),
&self.selected_deployment,
)? {
for key in st {
if let Ok(token) = self.dotrain_order.orderbook_yaml().get_token(&key) {
select_tokens.insert(key, token);
for select_token in st {
if let Ok(token) = self
.dotrain_order
.orderbook_yaml()
.get_token(&select_token.key)
{
select_tokens.insert(select_token.key, token);
}
}
}
Expand Down Expand Up @@ -191,7 +195,7 @@ impl DotrainOrderGui {
let select_tokens = deployment_select_tokens
.as_ref()
.ok_or(GuiError::SelectTokensNotSet)?;
if !select_tokens.contains(&key) {
if !select_tokens.iter().any(|token| token.key == key) {
return Err(GuiError::TokenNotInSelectTokens(key));
}
if dotrain_order_gui.is_select_token_set(key.clone())? {
Expand Down
120 changes: 99 additions & 21 deletions crates/settings/src/gui.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
yaml::{
context::{Context, GuiContextTrait},
default_document, get_hash_value, optional_hash, optional_string, optional_vec,
require_string, require_vec, FieldErrorKind, YamlError, YamlParsableHash,
default_document, get_hash_value, get_hash_value_as_option, optional_hash, optional_string,
optional_vec, require_string, require_vec, FieldErrorKind, YamlError, YamlParsableHash,
YamlParseableValue,
},
Deployment, Token, TokenRef,
Expand Down Expand Up @@ -60,7 +60,7 @@ pub struct GuiDeploymentSource {
pub deposits: Vec<GuiDepositSource>,
pub fields: Vec<GuiFieldDefinitionSource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub select_tokens: Option<Vec<TokenRef>>,
pub select_tokens: Option<Vec<GuiSelectTokens>>,
}

#[typeshare]
Expand Down Expand Up @@ -196,6 +196,15 @@ pub struct GuiDeposit {
#[cfg(target_family = "wasm")]
impl_all_wasm_traits!(GuiDeposit);

#[typeshare]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(target_family = "wasm", derive(Tsify))]
pub struct GuiSelectTokens {
pub key: TokenRef,
pub name: Option<String>,
pub description: Option<String>,
}

#[typeshare]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(target_family = "wasm", derive(Tsify))]
Expand All @@ -209,7 +218,7 @@ pub struct GuiDeployment {
pub description: String,
pub deposits: Vec<GuiDeposit>,
pub fields: Vec<GuiFieldDefinition>,
pub select_tokens: Option<Vec<String>>,
pub select_tokens: Option<Vec<GuiSelectTokens>>,
}
#[cfg(target_family = "wasm")]
impl_all_wasm_traits!(GuiDeployment);
Expand Down Expand Up @@ -299,7 +308,7 @@ impl Gui {
pub fn parse_select_tokens(
documents: Vec<Arc<RwLock<StrictYaml>>>,
deployment_key: &str,
) -> Result<Option<Vec<String>>, YamlError> {
) -> Result<Option<Vec<GuiSelectTokens>>, YamlError> {
for document in documents {
let document_read = document.read().map_err(|_| YamlError::ReadLockError)?;

Expand All @@ -314,9 +323,24 @@ impl Gui {
deployment_hash.get(&StrictYaml::String("select-tokens".to_string()))
{
let mut result = Vec::new();
for token in tokens {
if let StrictYaml::String(token_str) = token {
result.push(token_str.clone());
for (index, token) in tokens.iter().enumerate() {
if let StrictYaml::Hash(token_hash) = token {
let key = get_hash_value(token_hash, "key", Some(format!("key string missing for select-token index: {index} in gui deployment: {deployment_key}")))?.as_str().ok_or(YamlError::Field {
kind: FieldErrorKind::Missing("key".to_string()),
location: format!("select-token index: {index} in gui deployment: {deployment_key}"),
})?;
let name = get_hash_value_as_option(token_hash, "name")
.map(|s| s.as_str())
.unwrap_or_default();
let description =
get_hash_value_as_option(token_hash, "description")
.map(|s| s.as_str())
.unwrap_or_default();
result.push(GuiSelectTokens {
key: key.to_string(),
name: name.map(|s| s.to_string()),
description: description.map(|s| s.to_string()),
});
}
}
return Ok(Some(result));
Expand Down Expand Up @@ -570,20 +594,33 @@ impl YamlParseableValue for Gui {
.iter()
.enumerate()
.map(|(select_token_index, select_token_value)| {
Ok(select_token_value.as_str().ok_or(YamlError::Field {
let location = format!("select-token index '{select_token_index}' in gui deployment '{deployment_name}'");

select_token_value.as_hash().ok_or(YamlError::Field{
kind: FieldErrorKind::InvalidType {
field: "select-token".to_string(),
expected: "a string".to_string(),
expected: "a map".to_string(),
},
location: format!("select-token index '{select_token_index}' in {location}"),
})?.to_string())
location: location.clone(),
})?;

Ok(GuiSelectTokens {
key: require_string(select_token_value, Some("key"), Some(location.clone()))?,
name: optional_string(select_token_value, "name"),
description: optional_string(select_token_value, "description"),
})
.collect::<Result<Vec<_>, YamlError>>()?,
),
None => None,
};
})
.collect::<Result<Vec<_>, YamlError>>()?,
),
None => None,
};
if let Some(ref select_tokens) = select_tokens {
context.add_select_tokens(select_tokens.clone());
context.add_select_tokens(
select_tokens
.iter()
.map(|select_token| select_token.key.clone())
.collect::<Vec<_>>(),
);
}

let deployment = Deployment::parse_from_yaml(
Expand Down Expand Up @@ -807,7 +844,11 @@ mod tests {
]),
},
],
select_tokens: Some(vec!["test-token".to_string()]),
select_tokens: Some(vec![GuiSelectTokens {
key: "test-token".to_string(),
name: Some("Test name".to_string()),
description: Some("Test description".to_string()),
}]),
},
)]),
};
Expand Down Expand Up @@ -888,7 +929,11 @@ mod tests {
assert_eq!(presets[2].value, "true".to_string());
assert_eq!(
deployment.select_tokens,
Some(vec!["test-token".to_string()])
Some(vec![GuiSelectTokens {
key: "test-token".to_string(),
name: Some("Test name".to_string()),
description: Some("Test description".to_string()),
}])
);
}

Expand Down Expand Up @@ -1467,7 +1512,7 @@ gui:
presets:
- value: test
select-tokens:
- test: test
- test
"#;
let error = Gui::parse_from_yaml_optional(
vec![get_document(&format!("{yaml_prefix}{yaml}"))],
Expand All @@ -1479,11 +1524,44 @@ gui:
YamlError::Field {
kind: FieldErrorKind::InvalidType {
field: "select-token".to_string(),
expected: "a string".to_string()
expected: "a map".to_string()
},
location: "select-token index '0' in gui deployment 'deployment1'".to_string(),
}
);

let yaml = r#"
gui:
name: test
description: test
deployments:
deployment1:
name: test
description: test
deposits:
- token: token1
presets:
- "1"
fields:
- binding: test
name: test
presets:
- value: test
select-tokens:
- test: test
"#;
let error = Gui::parse_from_yaml_optional(
vec![get_document(&format!("{yaml_prefix}{yaml}"))],
None,
)
.unwrap_err();
assert_eq!(
error,
YamlError::Field {
kind: FieldErrorKind::Missing("key".to_string()),
location: "select-token index '0' in gui deployment 'deployment1'".to_string(),
}
);
}

#[test]
Expand Down
Loading

0 comments on commit a4da043

Please sign in to comment.