#![allow(clippy::expect_used)]
use gpui::{point, px, size, Bounds, TestAppContext};
use sqlly_datatable::pivot::PivotHitResult;
use sqlly_datatable::{
CellValue, Column, ColumnKind, GridData, GridTab, PivotConfig, PivotSidebarPosition,
SqllyDataTable,
};
#[gpui::test]
fn locked_pivot_stays_visible_but_rejects_activation(cx: &mut TestAppContext) {
let (view, cx) = cx.add_window_view(|_window, cx| {
let data = GridData::new(vec![], vec![]).expect("empty grid");
SqllyDataTable::builder(data)
.pivot(PivotConfig::default())
.build(cx)
});
view.update(cx, |table, cx| {
assert!(table.pivot_state().is_some(), "Pivot tab remains installed");
table.set_pivot_locked(true, Some("Loading".to_string()));
table.set_active_tab(GridTab::Pivot, cx);
assert!(table.pivot_locked());
assert_eq!(table.active_tab(), GridTab::Grid);
table.set_pivot_locked(false, None);
table.set_active_tab(GridTab::Pivot, cx);
assert!(!table.pivot_locked());
assert_eq!(table.active_tab(), GridTab::Pivot);
});
}
#[gpui::test]
fn pivot_sidebar_layout_is_configurable(cx: &mut TestAppContext) {
let (view, cx) = cx.add_window_view(|_window, cx| {
let data = GridData::new(vec![], vec![]).expect("empty grid");
SqllyDataTable::builder(data)
.pivot(PivotConfig::default())
.pivot_sidebar_position(PivotSidebarPosition::Right)
.pivot_sidebar_collapsed(true)
.pivot_sidebar_width(320.0)
.build(cx)
});
view.update(cx, |table, cx| {
assert_eq!(table.pivot_sidebar_position(), PivotSidebarPosition::Right);
assert!(table.pivot_sidebar_collapsed());
assert_eq!(table.pivot_sidebar_width(), 320.0);
table.set_pivot_sidebar_position(PivotSidebarPosition::Left);
table.set_pivot_sidebar_collapsed(false);
table.set_pivot_sidebar_width(0.0);
assert_eq!(table.pivot_sidebar_width(), 180.0);
table.set_pivot_sidebar_width(10_000.0);
assert_eq!(table.pivot_sidebar_position(), PivotSidebarPosition::Left);
assert!(!table.pivot_sidebar_collapsed());
assert_eq!(table.pivot_sidebar_width(), 480.0);
table.set_active_tab(GridTab::Pivot, cx);
});
cx.run_until_parked();
}
#[gpui::test]
fn pivot_save_config_button_is_wired_only_when_registered(cx: &mut TestAppContext) {
use std::cell::RefCell;
use std::rc::Rc;
let (view, cx) = cx.add_window_view(|_window, cx| {
let data = GridData::new(vec![], vec![]).expect("empty grid");
SqllyDataTable::builder(data)
.pivot(PivotConfig::default())
.build(cx)
});
view.update(cx, |table, cx| {
let pivot = table.pivot_state().expect("pivot state").clone();
assert!(!pivot.read(cx).has_save_config_handler());
let saved: Rc<RefCell<Option<PivotConfig>>> = Rc::new(RefCell::new(None));
let sink = saved.clone();
table.set_pivot_save_config(
move |config, _cx| {
*sink.borrow_mut() = Some(config.clone());
},
cx,
);
assert!(pivot.read(cx).has_save_config_handler());
pivot.update(cx, |state, cx| {
state.config.row_fields = vec![0];
let handler = state
.save_config_handler()
.expect("registered save handler");
handler(&state.config.clone(), cx);
});
assert_eq!(
saved.borrow().as_ref().map(|c| c.row_fields.clone()),
Some(vec![0])
);
table.clear_pivot_save_config(cx);
assert!(!pivot.read(cx).has_save_config_handler());
});
let (view, cx) = cx.add_window_view(|_window, cx| {
let data = GridData::new(vec![], vec![]).expect("empty grid");
SqllyDataTable::builder(data)
.pivot(PivotConfig::default())
.pivot_save_config(|_config, _cx| {})
.build(cx)
});
view.update(cx, |table, cx| {
let pivot = table.pivot_state().expect("pivot state");
assert!(pivot.read(cx).has_save_config_handler());
});
}
#[gpui::test]
fn pivot_dimensions_are_configurable_readable_and_resizable(cx: &mut TestAppContext) {
let (view, cx) = cx.add_window_view(|_window, cx| {
let data = GridData::new(
vec![
Column::new("region", ColumnKind::Text, 100.0),
Column::new("year", ColumnKind::Integer, 80.0),
Column::new("sales", ColumnKind::Integer, 100.0),
],
vec![
vec![
CellValue::Text("East".into()),
CellValue::Integer(2025),
CellValue::Integer(10),
],
vec![
CellValue::Text("West".into()),
CellValue::Integer(2025),
CellValue::Integer(20),
],
],
)
.expect("rectangular pivot data");
let config = PivotConfig {
row_fields: vec![0],
column_fields: vec![1],
value_field: Some(2),
..PivotConfig::default()
};
SqllyDataTable::builder(data)
.pivot(config)
.pivot_row_height(32.0)
.pivot_column_width(180.0)
.build(cx)
});
view.update(cx, |table, cx| {
let pivot = table.pivot_state().expect("pivot state");
pivot.update(cx, |state, _cx| {
assert_eq!(state.row_height(), 32.0);
assert_eq!(state.column_width(), 180.0);
state.set_row_height(1.0);
state.set_column_width(1.0);
assert_eq!(state.row_height(), 18.0);
assert_eq!(state.column_width(), 40.0);
state.set_row_height(32.0);
state.set_column_width(180.0);
state.bounds = Bounds {
origin: point(px(0.0), px(0.0)),
size: size(px(800.0), px(600.0)),
};
let column_edge = point(px(state.row_header_width + 180.0), px(10.0));
assert_eq!(
state.hit_test(column_edge),
PivotHitResult::ColBorder { col: 0 }
);
state.handle_mouse_down(column_edge, false);
state.handle_mouse_move(point(px(f32::from(column_edge.x) + 20.0), px(10.0)), true);
state.handle_mouse_up();
assert_eq!(state.column_width(), 200.0);
let row_edge = point(px(10.0), px(state.header_height() + 32.0));
assert_eq!(
state.hit_test(row_edge),
PivotHitResult::RowBorder { row: 0 }
);
state.handle_mouse_down(row_edge, false);
state.handle_mouse_move(point(px(10.0), px(f32::from(row_edge.y) + 8.0)), true);
state.handle_mouse_up();
assert_eq!(state.row_height(), 40.0);
});
});
}