sqlly_datatable/lib.rs
1//! Configurable virtualized data grid for the [GPUI] toolkit.
2//!
3//! `sqlly-datatable` provides a self-contained `Entity<GridState>` widget that
4//! you can drop into a GPUI application. It supports:
5//!
6//! * Virtualized rendering for large datasets.
7//! * Cell, row, column and rectangular drag selection.
8//! * Sorting on column headers, with a cycle through ascending, descending,
9//! and unsorted.
10//! * Per-column filtering via a rich filter panel (operator predicates,
11//! value checklist, search) opened from the built-in context menu.
12//! * Expandable row sections created by grouping on any column from its
13//! built-in context menu or through [`GridState::set_grouped_column`].
14//! * Configurable column resizing, mouse-driven scrollbars, and edge-scroll
15//! during drag selection.
16//! * Clipboard copy of any selection (with or without headers).
17//! * A restrained native motion layer: transient surfaces (context menus,
18//! filter panels, popovers, dialogs, the busy scrim, the pivot drag ghost)
19//! fade in on appear, while the data surface stays instant. On by default;
20//! set [`config::GridConfig::animations`] to `false` to honor a system
21//! reduce-motion preference.
22//! * An optional **pivot tab** ([`SqllyDataTableBuilder::pivot`]): a
23//! cross-tabulation view with a drag-and-drop field sidebar (rows /
24//! columns / values / filters), count/sum/avg/min/max aggregation,
25//! expandable row and column groups, subtotals and grand totals, sorting
26//! on labels or values, source-value filters, and CSV export. The pivot
27//! reads a shared snapshot of the grid's rows and never mutates them;
28//! switching tabs preserves both views' state. Configure it
29//! programmatically via [`pivot::PivotConfig`] and read the live layout
30//! back from [`pivot::PivotState::config`]. Pivot row height and column
31//! width can be initialized on the builder, resized in the view, and read
32//! or updated through [`pivot::PivotState`]. Right-clicks surface to a
33//! [`pivot::PivotContextMenuProvider`] with full context (grouping paths,
34//! aggregated value, driving source rows), and double-clicking any value
35//! cell drills through: the flat grid is filtered to exactly the rows
36//! behind that cell and brought to the front.
37//!
38//! The crate is intentionally GPUI-only on the UI side; the pure formatter in
39//! [`mod@format`] is usable in any context (export pipelines, server-side preview,
40//! etc.). All formatting is configurable per column by composing the
41//! [`config::GridConfig`] defaults with [`config::ColumnOverride`] entries.
42//!
43//! # Quick start
44//!
45//! ```no_run
46//! use gpui::App;
47//! use sqlly_datatable::{
48//! CellValue, Column, ColumnKind, GridConfig, GridData, SqllyDataTable,
49//! };
50//!
51//! // Inside your `gpui::Application::new().run(...)` closure (see the
52//! // sample app for a full bootstrap):
53//! fn setup(cx: &mut App) {
54//! sqlly_datatable::init(cx);
55//!
56//! let data = GridData::new(
57//! vec![Column { name: "id".into(), kind: ColumnKind::Integer, width: 80.0 }],
58//! vec![vec![CellValue::Integer(1)], vec![CellValue::Integer(2)]],
59//! ).expect("rectangular data");
60//! let _view = SqllyDataTable::builder(data)
61//! .config(GridConfig::default())
62//! .build(cx);
63//! }
64//! ```
65//!
66//! See `crates/sqlly-datatable-sample` for a runnable demo.
67//!
68//! [GPUI]: https://github.com/zed-industries/gpui
69
70// `missing_docs` is intentionally not enabled at the crate level. The public
71// surfaces documented here are stable; private internals will get docs as the
72// `grid::` modules mature. Run clippy with
73// `#![warn(missing_docs)]` in scope when cleaning up a module.
74
75pub mod config;
76pub mod data;
77pub mod filter;
78pub mod format;
79pub mod grid;
80pub mod pivot;
81
82// Re-exported so hosts can call `gpui_component` APIs (theme switching,
83// `Root`, other widgets) against the exact version this crate links,
84// guaranteeing type identity for globals like `gpui_component::Theme`.
85pub use gpui_component;
86// Re-exported so hosts can install the lucide icon SVGs this crate's chrome
87// renders (chevrons, close buttons, panel toggles, checkmarks):
88//
89// ```no_run
90// gpui::Application::new().with_assets(sqlly_datatable::gpui_component_assets::Assets)
91// # ;
92// ```
93//
94// Without an asset source providing `icons/*.svg`, those icons render empty
95// (with an error logged per icon).
96pub use gpui_component_assets;
97
98pub use config::{
99 BooleanFormat, ColumnOverride, DateFormat, GridConfig, KeyBinding, KeyBindings, NullFormat,
100 NumberFormat, RelativeDateFormat, RelativeUnit, ReplacementRule, ReplacementTiming,
101 ResolvedColumnFormat, StringFormat, TextAlignment, TextCase, TruncationBehavior,
102};
103pub use data::{
104 compare_cells, sample_data, CellValue, Column, ColumnKind, GridData, GridDataError,
105};
106pub use filter::{ColumnFilter, FilterPredicate, NumberOp, TextOp};
107pub use grid::{
108 BusyState, ColumnContext, ContextMenu, ContextMenuItem, ContextMenuProvider,
109 ContextMenuRequest, ContextMenuSelection, ContextMenuTarget, FilterPanel, GridState, GridTab,
110 GridTheme, GridThemePair, HitResult, MenuAction, MenuItem, PivotSidebarPosition, RowGroup,
111 RowWindow, ScrollbarAxis, SelectedCellContext, SelectedRowContext, Selection, SortDirection,
112 SqllyDataTable, SqllyDataTableBuilder,
113};
114pub use pivot::{
115 AggregationFn, PivotCellContext, PivotConfig, PivotContextMenuProvider,
116 PivotContextMenuRequest, PivotFormatDialog, PivotGrid, PivotMenuItem, PivotMenuTarget,
117 PivotPathComponent, PivotResult, PivotSaveConfigHandler, PivotSidebar, PivotSortKey,
118 PivotState, PivotZone, DEFAULT_PIVOT_COLUMN_WIDTH, DEFAULT_PIVOT_ROW_HEIGHT,
119 DEFAULT_PIVOT_SIDEBAR_WIDTH, MIN_PIVOT_COLUMN_WIDTH, MIN_PIVOT_ROW_HEADER_WIDTH,
120 MIN_PIVOT_ROW_HEIGHT,
121};
122
123/// Initialize the toolkit state this crate's widgets depend on. Call once at
124/// application startup, before opening any window that hosts a
125/// [`SqllyDataTable`]:
126///
127/// ```no_run
128/// fn setup(cx: &mut gpui::App) {
129/// sqlly_datatable::init(cx);
130/// // ... open windows ...
131/// }
132/// ```
133///
134/// This currently forwards to [`gpui_component::init`], which installs the
135/// global [`gpui_component::Theme`] used by the embedded `gpui-component`
136/// widgets (for example the pivot sidebar's resizable divider). Skipping it
137/// panics on first render of those widgets. Hosts that already call
138/// `gpui_component::init` themselves do not need to call this again.
139pub fn init(cx: &mut gpui::App) {
140 gpui_component::init(cx);
141}