use std::future::Future;
use ag_grid_core::{convert::ToJsValue, imports::log};
use ag_grid_derive::{FromInterface, ToJsValue as ToJsValueMacro};
use js_sys::Function;
use wasm_bindgen::{prelude::*, JsCast};
use wasm_bindgen_futures::spawn_local;
#[wasm_bindgen]
extern "C" {
pub(crate) type IGetRowsParams;
#[wasm_bindgen(method, getter, js_name = startRow)]
fn start_row(this: &IGetRowsParams) -> u32;
#[wasm_bindgen(method, getter, js_name = endRow)]
fn end_row(this: &IGetRowsParams) -> u32;
#[wasm_bindgen(method, getter, js_name = sortModel)]
fn sort_model(this: &IGetRowsParams) -> Vec<ISortModelItem>;
#[wasm_bindgen(method, getter, js_name = filterModel)]
fn filter_model(this: &IGetRowsParams) -> JsValue;
#[wasm_bindgen(method, getter, js_name = successCallback)]
fn success_callback(this: &IGetRowsParams) -> Function;
#[wasm_bindgen(method, getter, js_name = failCallback)]
fn fail_callback(this: &IGetRowsParams) -> Function;
}
#[derive(FromInterface, Debug)]
pub struct GetRowsParams {
pub start_row: u32,
pub end_row: u32,
pub sort_model: Vec<SortModelItem>,
}
#[wasm_bindgen]
extern "C" {
type ISortModelItem;
#[wasm_bindgen(method, getter, js_name = colId)]
fn col_id(this: &ISortModelItem) -> String;
#[wasm_bindgen(method, getter)]
fn sort(this: &ISortModelItem) -> SortDirection;
}
#[derive(Debug, FromInterface)]
pub struct SortModelItem {
pub col_id: String,
pub sort: SortDirection,
}
#[wasm_bindgen]
extern "C" {
pub(crate) type IHeaderValueGetterParams;
#[wasm_bindgen(method, getter, js_name = colId)]
pub(crate) fn location(this: &IHeaderValueGetterParams) -> Option<String>;
}
#[derive(Debug, FromInterface)]
pub struct HeaderValueGetterParams {
pub location: Option<String>,
}
#[wasm_bindgen]
#[derive(Debug)]
pub enum SortDirection {
Asc = "asc",
Desc = "desc",
}
#[wasm_bindgen]
#[derive(ToJsValueMacro)]
pub struct DataSource {
#[wasm_bindgen(readonly, getter_with_clone, js_name = getRows)]
pub get_rows: Function,
}
pub struct DataSourceBuilder {
get_rows: Closure<dyn FnMut(IGetRowsParams)>,
}
impl DataSourceBuilder {
pub fn new<F, Fut, T>(mut get_rows: F) -> Self
where
F: FnMut(GetRowsParams) -> Fut + 'static,
Fut: Future<Output = Result<(Vec<T>, Option<u32>), Box<dyn std::error::Error>>> + 'static,
T: ToJsValue,
{
let get_rows =
Closure::<dyn FnMut(IGetRowsParams)>::new(move |js_params: IGetRowsParams| {
let params = (&js_params).into();
let fut = get_rows(params);
let wrapper = async move {
match fut.await {
Ok((data, last_row_index)) => {
let data = data.to_js_value();
let last_row_index = last_row_index.to_js_value();
js_params
.success_callback()
.call2(&JsValue::null(), &data, &last_row_index)
.expect("failed calling success callback");
}
Err(e) => {
log(&format!("Error calling get_rows callback: {e:?}"));
js_params
.fail_callback()
.call0(&JsValue::null())
.expect("failed calling failure callback");
}
};
};
spawn_local(wrapper)
});
Self { get_rows }
}
pub fn build(self) -> DataSource {
DataSource {
get_rows: self.get_rows.into_js_value().unchecked_into(),
}
}
}
#[derive(ToJsValueMacro)]
pub enum SortMethod {
Asc,
Desc,
#[js_value(serialize_as = "null")]
Null,
}
#[derive(ToJsValueMacro)]
pub enum RowModelType {
Infinite,
Viewport,
ClientSide,
ServerSide,
}
#[derive(ToJsValueMacro)]
pub enum Filter {
AgNumberColumnFilter,
AgTextColumnFilter,
AgDateColumnFilter,
AgSetColumnFilter,
#[js_value(serialize_as = "true")]
True,
#[js_value(serialize_as = "false")]
False,
}
#[derive(ToJsValueMacro)]
pub enum LockPosition {
#[js_value(serialize_as = "true")]
True,
False,
Left,
Right,
}
#[derive(ToJsValueMacro)]
pub enum PinnedPosition {
#[js_value(serialize_as = "true")]
True,
False,
Left,
Right,
}
#[derive(ToJsValueMacro)]
pub enum PopupPosition {
Over,
Under,
}
#[allow(clippy::enum_variant_names)]
#[derive(ToJsValueMacro)]
pub enum MenuTab {
FilterMenuTab,
GeneralMenuTab,
ColumnsMenuTab,
}
pub(crate) enum OneOrMany<T>
where
T: ToJsValue,
{
One(T),
Many(Vec<T>),
}
impl<T> ToJsValue for OneOrMany<T>
where
T: ToJsValue,
{
fn to_js_value(&self) -> JsValue {
match self {
Self::One(v) => v.to_js_value(),
Self::Many(v) => v.to_js_value(),
}
}
}
impl<T> From<T> for OneOrMany<T>
where
T: ToJsValue,
{
fn from(v: T) -> Self {
Self::One(v)
}
}
impl<T> From<Vec<T>> for OneOrMany<T>
where
T: Into<OneOrMany<T>> + ToJsValue,
{
fn from(v: Vec<T>) -> Self {
Self::Many(v)
}
}