use perspective_client::config::{GroupRollupMode, SplitRollupMode};
use serde::Deserialize;
use ts_rs::TS;
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, TS)]
#[serde(rename_all = "camelCase")]
pub enum ColumnSelectMode {
#[default]
Toggle,
Select,
}
impl ColumnSelectMode {
pub fn css(&self) -> yew::Classes {
match self {
Self::Toggle => yew::classes!("toggle-mode", "is_column_active"),
Self::Select => yew::classes!("select-mode", "is_column_active"),
}
}
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, TS)]
pub struct PluginStaticConfig {
pub name: String,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub category: Option<String>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub max_columns: Option<usize>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub max_cells: Option<usize>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub select_mode: ColumnSelectMode,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub min_config_columns: Option<usize>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub config_column_names: Vec<String>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub group_rollup_modes: Option<Vec<GroupRollupMode>>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub split_rollup_modes: Option<Vec<SplitRollupMode>>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub priority: Option<i32>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub can_render_column_styles: bool,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub group_by_role: Option<String>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub split_by_role: Option<String>,
#[serde(default)]
#[ts(as = "Option<_>")]
#[ts(optional)]
pub connects_row_order: bool,
}
impl PluginStaticConfig {
pub fn positional_columns(&self) -> usize {
self.config_column_names.len().saturating_sub(1)
}
pub fn tail_column_role(&self) -> Option<&str> {
self.config_column_names.last().map(|x| x.as_str())
}
pub fn is_swap(&self, index: usize) -> bool {
!self.config_column_names.is_empty() && index < self.positional_columns()
}
pub fn get_group_rollups(&self, rollup_features: &[GroupRollupMode]) -> Vec<GroupRollupMode> {
self.group_rollup_modes
.clone()
.map(|x| {
x.into_iter()
.filter(|y| rollup_features.is_empty() || rollup_features.contains(y))
.collect()
})
.unwrap_or_default()
}
pub fn get_split_rollups(&self, rollup_features: &[SplitRollupMode]) -> Vec<SplitRollupMode> {
self.split_rollup_modes
.clone()
.map(|x| {
x.into_iter()
.filter(|y| rollup_features.is_empty() || rollup_features.contains(y))
.collect()
})
.unwrap_or_default()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn plugin(names: &[&str]) -> PluginStaticConfig {
PluginStaticConfig {
config_column_names: names.iter().map(|x| (*x).to_owned()).collect(),
..Default::default()
}
}
#[test]
fn positional_slots_and_tail_agree() {
let y_line = plugin(&["Y Axis"]);
assert_eq!(y_line.positional_columns(), 0);
assert_eq!(y_line.tail_column_role(), Some("Y Axis"));
assert!(!y_line.is_swap(0));
let xy_line = plugin(&["X Axis", "Y Axis", "Tooltip"]);
assert_eq!(xy_line.positional_columns(), 2);
assert_eq!(xy_line.tail_column_role(), Some("Tooltip"));
assert!(xy_line.is_swap(0));
assert!(xy_line.is_swap(1));
assert!(!xy_line.is_swap(2));
for index in 0..4 {
assert_eq!(xy_line.is_swap(index), index < xy_line.positional_columns());
}
let unnamed = plugin(&[]);
assert_eq!(unnamed.positional_columns(), 0);
assert_eq!(unnamed.tail_column_role(), None);
assert!(!unnamed.is_swap(0));
}
}