feat: config grid bloc

This commit is contained in:
appflowy
2022-03-03 22:17:07 +08:00
parent 0bbf17f776
commit 477fa5f4f6
41 changed files with 4209 additions and 905 deletions

View File

@ -57,6 +57,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "async-stream"
version = "0.3.2"
@ -1042,15 +1048,21 @@ dependencies = [
name = "flowy-grid"
version = "0.1.0"
dependencies = [
"bytes",
"chrono",
"flowy-derive",
"flowy-error",
"flowy-grid-data-model",
"lazy_static",
"lib-dispatch",
"lib-infra",
"protobuf",
"rust_decimal",
"rusty-money",
"strum",
"strum_macros",
"tracing",
"uuid",
]
[[package]]
@ -1061,6 +1073,8 @@ dependencies = [
"flowy-derive",
"lib-infra",
"protobuf",
"strum",
"strum_macros",
]
[[package]]
@ -1702,7 +1716,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
dependencies = [
"arrayvec",
"arrayvec 0.5.2",
"bitflags",
"cfg-if",
"ryu",
@ -2752,6 +2766,27 @@ dependencies = [
"winreg",
]
[[package]]
name = "rust_decimal"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d37baa70cf8662d2ba1c1868c5983dda16ef32b105cce41fb5c47e72936a90b3"
dependencies = [
"arrayvec 0.7.2",
"num-traits",
"serde",
]
[[package]]
name = "rust_decimal_macros"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "184abaf7b434800e1a5a8aad3ebc8cd7498df33af72d65371d797a264713a59b"
dependencies = [
"quote",
"rust_decimal",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
@ -2773,6 +2808,16 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "rusty-money"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b28f881005eac7ad8d46b6f075da5f322bd7f4f83a38720fc069694ddadd683"
dependencies = [
"rust_decimal",
"rust_decimal_macros",
]
[[package]]
name = "ryu"
version = "1.0.9"

View File

@ -15,6 +15,12 @@ strum_macros = "0.21"
flowy-derive = { path = "../../../shared-lib/flowy-derive" }
tracing = { version = "0.1", features = ["log"] }
protobuf = {version = "2.18.0"}
rust_decimal = "1.8.1"
rusty-money = {version = "0.4.0", features = ["iso"]}
lazy_static = "1.4.0"
chrono = "0.4.19"
uuid = { version = "0.8", features = ["serde", "v4"] }
bytes = { version = "1.0" }
[build-dependencies]
lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file_gen", "proto_gen"] }

View File

@ -1,3 +1,3 @@
proto_crates = ["src/event_map.rs"]
proto_crates = ["src/event_map.rs", "src/cell_service/cell_data.rs"]
event_files = ["src/event_map.rs"]

View File

@ -0,0 +1,469 @@
use crate::cell_service::util::*;
use crate::impl_any_data;
use bytes::Bytes;
use chrono::format::strftime::StrftimeItems;
use chrono::NaiveDateTime;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
use rust_decimal::Decimal;
use rusty_money::{
iso::{Currency, CNY, EUR, USD},
Money,
};
use std::str::FromStr;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
pub trait StringifyAnyData {
fn stringify_any_data(&self, data: &AnyData) -> String;
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError>;
}
pub trait DisplayCell {
fn display_content(&self, s: &str) -> String;
}
#[derive(Debug, Clone, ProtoBuf, Default)]
pub struct RichTextDescription {
#[pb(index = 1)]
pub format: String,
}
impl_any_data!(RichTextDescription, FieldType::RichText);
impl StringifyAnyData for RichTextDescription {
fn stringify_any_data(&self, data: &AnyData) -> String {
data.to_string()
}
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError> {
Ok(AnyData::from_str(&RichTextDescription::field_type(), s))
}
}
impl DisplayCell for RichTextDescription {
fn display_content(&self, s: &str) -> String {
s.to_string()
}
}
// Checkbox
#[derive(Debug, ProtoBuf, Default)]
pub struct CheckboxDescription {
#[pb(index = 1)]
pub is_selected: bool,
}
impl_any_data!(CheckboxDescription, FieldType::Checkbox);
impl StringifyAnyData for CheckboxDescription {
fn stringify_any_data(&self, data: &AnyData) -> String {
data.to_string()
}
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError> {
let s = match string_to_bool(s) {
true => "1",
false => "0",
};
Ok(AnyData::from_str(&CheckboxDescription::field_type(), s))
}
}
impl DisplayCell for CheckboxDescription {
fn display_content(&self, s: &str) -> String {
s.to_string()
}
}
// Date
#[derive(Clone, Debug, ProtoBuf)]
pub struct DateDescription {
#[pb(index = 1)]
pub date_format: DateFormat,
#[pb(index = 2)]
pub time_format: TimeFormat,
}
impl_any_data!(DateDescription, FieldType::DateTime);
impl std::default::Default for DateDescription {
fn default() -> Self {
DateDescription {
date_format: DateFormat::default(),
time_format: TimeFormat::default(),
}
}
}
impl DateDescription {
fn date_time_format_str(&self) -> String {
format!("{} {}", self.date_format.format_str(), self.time_format.format_str())
}
#[allow(dead_code)]
fn today_from_timestamp(&self, timestamp: i64) -> String {
let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
self.today_from_native(native)
}
fn today_from_native(&self, naive: chrono::NaiveDateTime) -> String {
let utc: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_utc(naive, chrono::Utc);
let local: chrono::DateTime<chrono::Local> = chrono::DateTime::from(utc);
let fmt_str = self.date_time_format_str();
let output = format!("{}", local.format_with_items(StrftimeItems::new(&fmt_str)));
output
}
}
impl DisplayCell for DateDescription {
fn display_content(&self, s: &str) -> String {
match s.parse::<i64>() {
Ok(timestamp) => {
let native = NaiveDateTime::from_timestamp(timestamp, 0);
self.today_from_native(native)
}
Err(e) => {
tracing::debug!("DateDescription format {} fail. error: {:?}", s, e);
String::new()
}
}
}
}
impl StringifyAnyData for DateDescription {
fn stringify_any_data(&self, data: &AnyData) -> String {
match String::from_utf8(data.value.clone()) {
Ok(s) => match s.parse::<i64>() {
Ok(timestamp) => {
let native = NaiveDateTime::from_timestamp(timestamp, 0);
self.today_from_native(native)
}
Err(e) => {
tracing::debug!("DateDescription format {} fail. error: {:?}", s, e);
String::new()
}
},
Err(e) => {
tracing::error!("DateDescription stringify any_data failed. {:?}", e);
String::new()
}
}
}
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError> {
let timestamp = s
.parse::<i64>()
.map_err(|e| FlowyError::internal().context(format!("Parse {} to i64 failed: {}", s, e)))?;
Ok(AnyData::from_str(
&DateDescription::field_type(),
&format!("{}", timestamp),
))
}
}
#[derive(Clone, Debug, Copy, ProtoBuf_Enum)]
pub enum DateFormat {
Local = 0,
US = 1,
ISO = 2,
Friendly = 3,
}
impl std::default::Default for DateFormat {
fn default() -> Self {
DateFormat::Friendly
}
}
impl std::convert::From<i32> for DateFormat {
fn from(value: i32) -> Self {
match value {
0 => DateFormat::Local,
1 => DateFormat::US,
2 => DateFormat::ISO,
3 => DateFormat::Friendly,
_ => {
tracing::error!("Unsupported date format, fallback to friendly");
DateFormat::Friendly
}
}
}
}
impl DateFormat {
pub fn value(&self) -> i32 {
*self as i32
}
// https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
pub fn format_str(&self) -> &'static str {
match self {
DateFormat::Local => "%Y/%m/%d",
DateFormat::US => "%Y/%m/%d",
DateFormat::ISO => "%Y-%m-%d",
DateFormat::Friendly => "%b %d,%Y",
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, ProtoBuf_Enum)]
pub enum TimeFormat {
TwelveHour = 0,
TwentyFourHour = 1,
}
impl std::convert::From<i32> for TimeFormat {
fn from(value: i32) -> Self {
match value {
0 => TimeFormat::TwelveHour,
1 => TimeFormat::TwentyFourHour,
_ => {
tracing::error!("Unsupported time format, fallback to TwentyFourHour");
TimeFormat::TwentyFourHour
}
}
}
}
impl TimeFormat {
pub fn value(&self) -> i32 {
*self as i32
}
// https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
pub fn format_str(&self) -> &'static str {
match self {
TimeFormat::TwelveHour => "%r",
TimeFormat::TwentyFourHour => "%R",
}
}
}
impl std::default::Default for TimeFormat {
fn default() -> Self {
TimeFormat::TwentyFourHour
}
}
// Single select
#[derive(Clone, Debug, ProtoBuf, Default)]
pub struct SingleSelect {
#[pb(index = 1)]
pub options: Vec<SelectOption>,
#[pb(index = 2)]
pub disable_color: bool,
}
impl_any_data!(SingleSelect, FieldType::SingleSelect);
impl StringifyAnyData for SingleSelect {
fn stringify_any_data(&self, data: &AnyData) -> String {
data.to_string()
}
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError> {
Ok(AnyData::from_str(&SingleSelect::field_type(), s))
}
}
impl DisplayCell for SingleSelect {
fn display_content(&self, s: &str) -> String {
s.to_string()
}
}
// Multiple select
#[derive(Clone, Debug, ProtoBuf, Default)]
pub struct MultiSelect {
#[pb(index = 1)]
pub options: Vec<SelectOption>,
#[pb(index = 2)]
pub disable_color: bool,
}
impl_any_data!(MultiSelect, FieldType::MultiSelect);
impl StringifyAnyData for MultiSelect {
fn stringify_any_data(&self, data: &AnyData) -> String {
data.to_string()
}
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError> {
Ok(AnyData::from_str(&MultiSelect::field_type(), s))
}
}
impl DisplayCell for MultiSelect {
fn display_content(&self, s: &str) -> String {
s.to_string()
}
}
#[derive(Clone, Debug, ProtoBuf, Default)]
pub struct SelectOption {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2)]
pub name: String,
#[pb(index = 3)]
pub color: String,
}
impl SelectOption {
pub fn new(name: &str) -> Self {
SelectOption {
id: uuid(),
name: name.to_owned(),
color: "".to_string(),
}
}
}
// Number
#[derive(Clone, Debug, ProtoBuf)]
pub struct NumberDescription {
#[pb(index = 1)]
pub money: FlowyMoney,
#[pb(index = 2)]
pub scale: u32,
#[pb(index = 3)]
pub symbol: String,
#[pb(index = 4)]
pub sign_positive: bool,
#[pb(index = 5)]
pub name: String,
}
impl_any_data!(NumberDescription, FieldType::Number);
impl std::default::Default for NumberDescription {
fn default() -> Self {
NumberDescription {
money: FlowyMoney::default(),
scale: 0,
symbol: String::new(),
sign_positive: true,
name: String::new(),
}
}
}
impl NumberDescription {
pub fn set_money(&mut self, money: FlowyMoney) {
self.money = money;
self.symbol = money.symbol();
}
fn money_from_str(&self, s: &str) -> Option<String> {
match Decimal::from_str(s) {
Ok(mut decimal) => {
match decimal.set_scale(self.scale) {
Ok(_) => {}
Err(e) => {
tracing::error!("Set decimal scale failed: {:?}", e);
}
}
decimal.set_sign_positive(self.sign_positive);
Some(self.money.with_decimal(decimal).to_string())
}
Err(e) => {
tracing::error!("Parser money from {} failed: {:?}", s, e);
None
}
}
}
}
impl DisplayCell for NumberDescription {
fn display_content(&self, s: &str) -> String {
match self.money_from_str(&s) {
Some(money_str) => money_str,
None => String::default(),
}
}
}
impl StringifyAnyData for NumberDescription {
fn stringify_any_data(&self, data: &AnyData) -> String {
match String::from_utf8(data.value.clone()) {
Ok(s) => match self.money_from_str(&s) {
Some(money_str) => money_str,
None => String::default(),
},
Err(e) => {
tracing::error!("NumberDescription stringify any_data failed. {:?}", e);
String::new()
}
}
}
fn str_to_any_data(&self, s: &str) -> Result<AnyData, FlowyError> {
let strip_symbol_money = strip_money_symbol(s);
let decimal = Decimal::from_str(&strip_symbol_money).map_err(|err| FlowyError::internal().context(err))?;
let money_str = decimal.to_string();
Ok(AnyData::from_str(&NumberDescription::field_type(), &money_str))
}
}
#[derive(Clone, Copy, Debug, EnumIter, ProtoBuf_Enum)]
pub enum FlowyMoney {
CNY = 0,
EUR = 1,
USD = 2,
}
impl std::default::Default for FlowyMoney {
fn default() -> Self {
FlowyMoney::USD
}
}
impl FlowyMoney {
// Currency list https://docs.rs/rusty-money/0.4.0/rusty_money/iso/index.html
pub fn from_str(s: &str) -> FlowyMoney {
match s {
"CNY" => FlowyMoney::CNY,
"EUR" => FlowyMoney::EUR,
"USD" => FlowyMoney::USD,
_ => FlowyMoney::CNY,
}
}
pub fn from_money(money: &rusty_money::Money<Currency>) -> FlowyMoney {
FlowyMoney::from_str(&money.currency().symbol.to_string())
}
pub fn currency(&self) -> &'static Currency {
match self {
FlowyMoney::CNY => CNY,
FlowyMoney::EUR => EUR,
FlowyMoney::USD => USD,
}
}
// string_to_money("¥18,443").unwrap();
// string_to_money("$18,443").unwrap();
// string_to_money("€18,443").unwrap();
pub fn code(&self) -> String {
self.currency().iso_alpha_code.to_string()
}
pub fn symbol(&self) -> String {
self.currency().symbol.to_string()
}
pub fn zero(&self) -> Money<Currency> {
let mut decimal = Decimal::new(0, 0);
decimal.set_sign_positive(true);
self.with_decimal(decimal)
}
pub fn with_decimal(&self, decimal: Decimal) -> Money<Currency> {
let money = rusty_money::Money::from_decimal(decimal, self.currency());
money
}
}

View File

@ -0,0 +1,5 @@
mod stringify;
mod util;
pub mod cell_data;
pub use stringify::*;

View File

@ -0,0 +1,30 @@
use crate::cell_service::cell_data::*;
use crate::cell_service::util::*;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
pub trait AnyDataSerde {
fn serialize(field: &Field, s: &str) -> Result<AnyData, FlowyError> {
match field.field_type {
FieldType::RichText => RichTextDescription::from(field).str_to_any_data(s),
FieldType::Number => NumberDescription::from(field).str_to_any_data(s),
FieldType::DateTime => DateDescription::from(field).str_to_any_data(s),
FieldType::SingleSelect => SingleSelect::from(field).str_to_any_data(s),
FieldType::MultiSelect => MultiSelect::from(field).str_to_any_data(s),
FieldType::Checkbox => CheckboxDescription::from(field).str_to_any_data(s),
}
}
fn deserialize(data: &AnyData, field: &Field) -> Result<String, FlowyError> {
let _ = check_type_id(data, field)?;
let s = match field.field_type {
FieldType::RichText => RichTextDescription::from(field).stringify_any_data(data),
FieldType::Number => NumberDescription::from(field).stringify_any_data(data),
FieldType::DateTime => DateDescription::from(field).stringify_any_data(data),
FieldType::SingleSelect => SingleSelect::from(field).stringify_any_data(data),
FieldType::MultiSelect => MultiSelect::from(field).stringify_any_data(data),
FieldType::Checkbox => CheckboxDescription::from(field).stringify_any_data(data),
};
Ok(s)
}
}

View File

@ -0,0 +1,129 @@
use crate::cell_service::cell_data::FlowyMoney;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
use lazy_static::lazy_static;
use rust_decimal::Decimal;
use rusty_money::{iso::Currency, Money};
use std::collections::HashMap;
use std::str::FromStr;
use strum::IntoEnumIterator;
lazy_static! {
static ref CURRENCIES_BY_SYMBOL: HashMap<String, &'static Currency> = generate_currency_by_symbol();
}
#[allow(dead_code)]
fn generate_currency_by_symbol() -> HashMap<String, &'static Currency> {
let mut map: HashMap<String, &'static Currency> = HashMap::new();
for money in FlowyMoney::iter() {
map.insert(money.symbol(), money.currency());
}
map
}
#[allow(dead_code)]
pub fn string_to_money(money_str: &str) -> Option<Money<Currency>> {
let mut process_money_str = String::from(money_str);
let default_currency = FlowyMoney::from_str("CNY").currency();
if process_money_str.is_empty() {
return None;
}
return if process_money_str.chars().all(char::is_numeric) {
match Money::from_str(&process_money_str, default_currency) {
Ok(money) => Some(money),
Err(_) => None,
}
} else {
let symbol = process_money_str.chars().next().unwrap().to_string();
let mut currency = default_currency;
for key in CURRENCIES_BY_SYMBOL.keys() {
if symbol.eq(key) {
currency = CURRENCIES_BY_SYMBOL.get(key).unwrap();
crop_letters(&mut process_money_str, 1);
}
}
match Money::from_str(&process_money_str, currency) {
Ok(money) => Some(money),
Err(_) => None,
}
};
}
#[allow(dead_code)]
pub fn money_from_str(s: &str) -> Option<String> {
match Decimal::from_str(s) {
Ok(mut decimal) => {
match decimal.set_scale(0) {
Ok(_) => {}
Err(e) => {
tracing::error!("Set scale failed. {:?}", e);
}
}
decimal.set_sign_positive(true);
Some(FlowyMoney::USD.with_decimal(decimal).to_string())
}
Err(e) => {
tracing::debug!("Format {} to money failed, {:?}", s, e);
None
}
}
}
pub fn strip_money_symbol(money_str: &str) -> String {
let mut process_money_str = String::from(money_str);
if !process_money_str.chars().all(char::is_numeric) {
let symbol = process_money_str.chars().next().unwrap().to_string();
for key in CURRENCIES_BY_SYMBOL.keys() {
if symbol.eq(key) {
crop_letters(&mut process_money_str, 1);
}
}
}
process_money_str
}
fn crop_letters(s: &mut String, pos: usize) {
match s.char_indices().nth(pos) {
Some((pos, _)) => {
s.drain(..pos);
}
None => {
s.clear();
}
}
}
pub fn string_to_bool(bool_str: &str) -> bool {
let lower_case_str: &str = &bool_str.to_lowercase();
match lower_case_str {
"1" => true,
"true" => true,
"yes" => true,
"0" => false,
"false" => false,
"no" => false,
_ => false,
}
}
pub fn uuid() -> String {
uuid::Uuid::new_v4().to_string()
}
pub fn check_type_id(data: &AnyData, field: &Field) -> Result<(), FlowyError> {
let field_type = FieldType::from_type_id(&data.type_id).map_err(|e| FlowyError::internal().context(e))?;
if field_type != field.field_type {
tracing::error!(
"expected field type: {:?} but receive {:?} ",
field_type,
field.field_type
);
}
Ok(())
}

View File

@ -1,7 +1,9 @@
use crate::controller::GridManager;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{CreateGridPayload, Grid, GridId};
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
use flowy_grid_data_model::entities::{
CreateGridPayload, Grid, GridId, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
};
use lib_dispatch::prelude::{AppData, Data, DataResult};
use std::sync::Arc;
#[tracing::instrument(skip(data, controller), err)]
@ -17,7 +19,37 @@ pub(crate) async fn open_grid_handler(
data: Data<GridId>,
controller: AppData<Arc<GridManager>>,
) -> DataResult<Grid, FlowyError> {
let params: GridId = data.into_inner();
let _params: GridId = data.into_inner();
todo!()
}
#[tracing::instrument(skip(data, controller), err)]
pub(crate) async fn get_rows_handler(
data: Data<RepeatedRowOrder>,
controller: AppData<Arc<GridManager>>,
) -> DataResult<Grid, FlowyError> {
let row_orders: RepeatedRowOrder = data.into_inner();
todo!()
}
#[tracing::instrument(skip(data, controller), err)]
pub(crate) async fn get_fields_handler(
data: Data<RepeatedFieldOrder>,
controller: AppData<Arc<GridManager>>,
) -> DataResult<Grid, FlowyError> {
let field_orders: RepeatedFieldOrder = data.into_inner();
todo!()
}
#[tracing::instrument(skip(data, controller), err)]
pub(crate) async fn create_row_handler(
data: Data<GridId>,
controller: AppData<Arc<GridManager>>,
) -> DataResult<Grid, FlowyError> {
let id: GridId = data.into_inner();
todo!()
}

View File

@ -7,10 +7,12 @@ use strum_macros::Display;
pub fn create(grid_manager: Arc<GridManager>) -> Module {
let mut module = Module::new().name(env!("CARGO_PKG_NAME")).data(grid_manager);
module = module
.event(GridEvent::CreateGrid, create_grid_handler)
.event(GridEvent::OpenGrid, open_grid_handler);
.event(GridEvent::OpenGrid, open_grid_handler)
.event(GridEvent::GetRows, get_rows_handler)
.event(GridEvent::GetFields, get_fields_handler)
.event(GridEvent::CreateRow, create_row_handler);
module
}
@ -23,4 +25,13 @@ pub enum GridEvent {
#[event(input = "GridId", output = "Grid")]
OpenGrid = 1,
#[event(input = "RepeatedRowOrder", output = "RepeatedRow")]
GetRows = 2,
#[event(input = "RepeatedFieldOrder", output = "RepeatedField")]
GetFields = 3,
#[event(input = "GridId")]
CreateRow = 4,
}

View File

@ -1,5 +1,9 @@
#[macro_use]
mod macros;
mod controller;
mod event_handler;
mod event_map;
mod cell_service;
mod protobuf;

View File

@ -0,0 +1,64 @@
#[macro_export]
macro_rules! impl_any_data {
($target: ident, $field_type:expr) => {
impl_field_type_data_from_field!($target);
impl_field_type_data_from_field_type_option!($target);
impl_type_option_from_field_data!($target, $field_type);
};
}
#[macro_export]
macro_rules! impl_field_type_data_from_field {
($target: ident) => {
impl std::convert::From<&Field> for $target {
fn from(field: &Field) -> $target {
$target::from(&field.type_options)
}
}
};
}
#[macro_export]
macro_rules! impl_field_type_data_from_field_type_option {
($target: ident) => {
impl std::convert::From<&AnyData> for $target {
fn from(any_data: &AnyData) -> $target {
match $target::try_from(Bytes::from(any_data.value.clone())) {
Ok(obj) => obj,
Err(err) => {
tracing::error!("{} convert from any data failed, {:?}", stringify!($target), err);
$target::default()
}
}
}
}
};
}
#[macro_export]
macro_rules! impl_type_option_from_field_data {
($target: ident, $field_type:expr) => {
impl $target {
pub fn field_type() -> FieldType {
$field_type
}
}
impl std::convert::From<$target> for AnyData {
fn from(field_data: $target) -> Self {
match field_data.try_into() {
Ok(bytes) => {
let bytes: Bytes = bytes;
AnyData::from_bytes(&$target::field_type(), bytes)
}
Err(e) => {
tracing::error!("Field type data convert to AnyData fail, error: {:?}", e);
// it's impossible to fail when unwrapping the default field type data
let default_bytes: Bytes = $target::default().try_into().unwrap();
AnyData::from_bytes(&$target::field_type(), default_bytes)
}
}
}
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,9 @@
pub enum GridEvent {
CreateGrid = 0,
OpenGrid = 1,
GetRows = 2,
GetFields = 3,
CreateRow = 4,
}
impl ::protobuf::ProtobufEnum for GridEvent {
@ -38,6 +41,9 @@ impl ::protobuf::ProtobufEnum for GridEvent {
match value {
0 => ::std::option::Option::Some(GridEvent::CreateGrid),
1 => ::std::option::Option::Some(GridEvent::OpenGrid),
2 => ::std::option::Option::Some(GridEvent::GetRows),
3 => ::std::option::Option::Some(GridEvent::GetFields),
4 => ::std::option::Option::Some(GridEvent::CreateRow),
_ => ::std::option::Option::None
}
}
@ -46,6 +52,9 @@ impl ::protobuf::ProtobufEnum for GridEvent {
static values: &'static [GridEvent] = &[
GridEvent::CreateGrid,
GridEvent::OpenGrid,
GridEvent::GetRows,
GridEvent::GetFields,
GridEvent::CreateRow,
];
values
}
@ -74,8 +83,9 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0fevent_map.proto*)\n\tGridEvent\x12\x0e\n\nCreateGrid\x10\0\x12\x0c\
\n\x08OpenGrid\x10\x01b\x06proto3\
\n\x0fevent_map.proto*T\n\tGridEvent\x12\x0e\n\nCreateGrid\x10\0\x12\x0c\
\n\x08OpenGrid\x10\x01\x12\x0b\n\x07GetRows\x10\x02\x12\r\n\tGetFields\
\x10\x03\x12\r\n\tCreateRow\x10\x04b\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -1,5 +1,8 @@
#![cfg_attr(rustfmt, rustfmt::skip)]
// Auto-generated, do not edit
mod cell_data;
pub use cell_data::*;
mod event_map;
pub use event_map::*;

View File

@ -0,0 +1,47 @@
syntax = "proto3";
message RichTextDescription {
string format = 1;
}
message CheckboxDescription {
bool is_selected = 1;
}
message DateDescription {
DateFormat date_format = 1;
TimeFormat time_format = 2;
}
message SingleSelect {
repeated SelectOption options = 1;
bool disable_color = 2;
}
message MultiSelect {
repeated SelectOption options = 1;
bool disable_color = 2;
}
message SelectOption {
string id = 1;
string name = 2;
string color = 3;
}
message NumberDescription {
FlowyMoney money = 1;
uint32 scale = 2;
string symbol = 3;
bool sign_positive = 4;
string name = 5;
}
enum DateFormat {
Local = 0;
US = 1;
ISO = 2;
Friendly = 3;
}
enum TimeFormat {
TwelveHour = 0;
TwentyFourHour = 1;
}
enum FlowyMoney {
CNY = 0;
EUR = 1;
USD = 2;
}

View File

@ -3,4 +3,7 @@ syntax = "proto3";
enum GridEvent {
CreateGrid = 0;
OpenGrid = 1;
GetRows = 2;
GetFields = 3;
CreateRow = 4;
}