mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: number cell format (#1623)
Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
parent
5c1b084789
commit
a2b5d6fa99
@ -229,11 +229,14 @@ pub(crate) async fn move_field_handler(
|
|||||||
|
|
||||||
/// The [FieldRevision] contains multiple data, each of them belongs to a specific FieldType.
|
/// The [FieldRevision] contains multiple data, each of them belongs to a specific FieldType.
|
||||||
async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) -> FlowyResult<Vec<u8>> {
|
async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) -> FlowyResult<Vec<u8>> {
|
||||||
let s = field_rev.get_type_option_str(field_type).unwrap_or_else(|| {
|
let s = field_rev
|
||||||
default_type_option_builder_from_type(field_type)
|
.get_type_option_str(field_type)
|
||||||
.serializer()
|
.map(|value| value.to_owned())
|
||||||
.json_str()
|
.unwrap_or_else(|| {
|
||||||
});
|
default_type_option_builder_from_type(field_type)
|
||||||
|
.serializer()
|
||||||
|
.json_str()
|
||||||
|
});
|
||||||
let field_type: FieldType = field_rev.ty.into();
|
let field_type: FieldType = field_rev.ty.into();
|
||||||
let builder = type_option_builder_from_json_str(&s, &field_type);
|
let builder = type_option_builder_from_json_str(&s, &field_type);
|
||||||
let type_option_data = builder.serializer().protobuf_bytes().to_vec();
|
let type_option_data = builder.serializer().protobuf_bytes().to_vec();
|
||||||
|
@ -41,7 +41,7 @@ pub trait CellDataChangeset: TypeOption {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
type_cell_data: Option<TypeCellData>,
|
type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData>;
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// changeset: It will be deserialized into specific data base on the FieldType.
|
/// changeset: It will be deserialized into specific data base on the FieldType.
|
||||||
@ -65,13 +65,13 @@ pub fn apply_cell_data_changeset<C: ToCellChangesetString, T: AsRef<FieldRevisio
|
|||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let cell_data = match TypeOptionCellExt::new_with_cell_data_cache(field_rev, cell_data_cache)
|
let cell_str = match TypeOptionCellExt::new_with_cell_data_cache(field_rev, cell_data_cache)
|
||||||
.get_type_option_cell_data_handler(&field_type)
|
.get_type_option_cell_data_handler(&field_type)
|
||||||
{
|
{
|
||||||
None => "".to_string(),
|
None => "".to_string(),
|
||||||
Some(handler) => handler.handle_cell_changeset(changeset, type_cell_data, field_rev)?,
|
Some(handler) => handler.handle_cell_changeset(changeset, type_cell_data, field_rev)?,
|
||||||
};
|
};
|
||||||
Ok(TypeCellData::new(cell_data, field_type).to_json())
|
Ok(TypeCellData::new(cell_str, field_type).to_json())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_type_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug>(
|
pub fn decode_type_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug>(
|
||||||
|
@ -82,11 +82,8 @@ impl std::convert::TryFrom<CellRevision> for TypeCellData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeCellData {
|
impl TypeCellData {
|
||||||
pub fn new(content: String, field_type: FieldType) -> Self {
|
pub fn new(cell_str: String, field_type: FieldType) -> Self {
|
||||||
TypeCellData {
|
TypeCellData { cell_str, field_type }
|
||||||
cell_str: content,
|
|
||||||
field_type,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_json(&self) -> String {
|
pub fn to_json(&self) -> String {
|
||||||
|
@ -87,9 +87,9 @@ impl CellDataChangeset for CheckboxTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
_type_cell_data: Option<TypeCellData>,
|
_type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let checkbox_cell_data = CheckboxCellData::from_str(&changeset)?;
|
let checkbox_cell_data = CheckboxCellData::from_str(&changeset)?;
|
||||||
Ok(checkbox_cell_data)
|
Ok((checkbox_cell_data.to_string(), checkbox_cell_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,17 +152,17 @@ mod tests {
|
|||||||
time: include_time_str,
|
time: include_time_str,
|
||||||
is_utc: false,
|
is_utc: false,
|
||||||
};
|
};
|
||||||
let encoded_data = type_option.apply_changeset(changeset, None).unwrap();
|
let (cell_str, _) = type_option.apply_changeset(changeset, None).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
decode_cell_data(encoded_data.to_string(), type_option, field_rev),
|
decode_cell_data(cell_str, type_option, field_rev),
|
||||||
expected_str.to_owned(),
|
expected_str.to_owned(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_cell_data(encoded_data: String, type_option: &DateTypeOptionPB, field_rev: &FieldRevision) -> String {
|
fn decode_cell_data(cell_str: String, type_option: &DateTypeOptionPB, field_rev: &FieldRevision) -> String {
|
||||||
let decoded_data = type_option
|
let decoded_data = type_option
|
||||||
.decode_cell_str(encoded_data, &FieldType::DateTime, field_rev)
|
.decode_cell_str(cell_str, &FieldType::DateTime, field_rev)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let decoded_data = type_option.convert_to_protobuf(decoded_data);
|
let decoded_data = type_option.convert_to_protobuf(decoded_data);
|
||||||
if type_option.include_time {
|
if type_option.include_time {
|
||||||
|
@ -157,7 +157,7 @@ impl CellDataChangeset for DateTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
_type_cell_data: Option<TypeCellData>,
|
_type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let cell_data = match changeset.date_timestamp() {
|
let cell_data = match changeset.date_timestamp() {
|
||||||
None => 0,
|
None => 0,
|
||||||
Some(date_timestamp) => match (self.include_time, changeset.time) {
|
Some(date_timestamp) => match (self.include_time, changeset.time) {
|
||||||
@ -171,8 +171,8 @@ impl CellDataChangeset for DateTypeOptionPB {
|
|||||||
_ => date_timestamp,
|
_ => date_timestamp,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
let date_cell_data = DateCellData(Some(cell_data));
|
||||||
Ok(DateCellData(Some(cell_data)))
|
Ok((date_cell_data.to_string(), date_cell_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ impl ToCellChangesetString for DateCellChangeset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct DateCellData(pub Option<i64>);
|
pub struct DateCellData(pub Option<i64>);
|
||||||
|
|
||||||
impl std::convert::From<DateCellData> for i64 {
|
impl std::convert::From<DateCellData> for i64 {
|
||||||
|
@ -155,10 +155,10 @@ impl CellDataChangeset for NumberTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
_type_cell_data: Option<TypeCellData>,
|
_type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let data = changeset.trim().to_string();
|
let data = changeset.trim().to_string();
|
||||||
let _ = self.format_cell_data(&data)?;
|
let number_cell_data = self.format_cell_data(&data)?;
|
||||||
Ok(StrCellData(data))
|
Ok((data, number_cell_data.to_string().into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,15 +60,15 @@ impl CellDataChangeset for ChecklistTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
type_cell_data: Option<TypeCellData>,
|
type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let insert_option_ids = changeset
|
let insert_option_ids = changeset
|
||||||
.insert_option_ids
|
.insert_option_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
|
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
match type_cell_data {
|
let select_option_ids = match type_cell_data {
|
||||||
None => Ok(SelectOptionIds::from(insert_option_ids)),
|
None => SelectOptionIds::from(insert_option_ids),
|
||||||
Some(type_cell_data) => {
|
Some(type_cell_data) => {
|
||||||
let mut select_ids: SelectOptionIds = type_cell_data.cell_str.into();
|
let mut select_ids: SelectOptionIds = type_cell_data.cell_str.into();
|
||||||
for insert_option_id in insert_option_ids {
|
for insert_option_id in insert_option_ids {
|
||||||
@ -81,9 +81,10 @@ impl CellDataChangeset for ChecklistTypeOptionPB {
|
|||||||
select_ids.retain(|id| id != &delete_option_id);
|
select_ids.retain(|id| id != &delete_option_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(select_ids)
|
select_ids
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
Ok((select_option_ids.to_string(), select_option_ids))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TypeOptionCellDataFilter for ChecklistTypeOptionPB {
|
impl TypeOptionCellDataFilter for ChecklistTypeOptionPB {
|
||||||
|
@ -61,15 +61,15 @@ impl CellDataChangeset for MultiSelectTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
type_cell_data: Option<TypeCellData>,
|
type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let insert_option_ids = changeset
|
let insert_option_ids = changeset
|
||||||
.insert_option_ids
|
.insert_option_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
|
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
match type_cell_data {
|
let select_option_ids = match type_cell_data {
|
||||||
None => Ok(SelectOptionIds::from(insert_option_ids)),
|
None => SelectOptionIds::from(insert_option_ids),
|
||||||
Some(type_cell_data) => {
|
Some(type_cell_data) => {
|
||||||
let mut select_ids: SelectOptionIds = type_cell_data.cell_str.into();
|
let mut select_ids: SelectOptionIds = type_cell_data.cell_str.into();
|
||||||
for insert_option_id in insert_option_ids {
|
for insert_option_id in insert_option_ids {
|
||||||
@ -83,9 +83,10 @@ impl CellDataChangeset for MultiSelectTypeOptionPB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("Multi-select cell data: {}", select_ids.to_string());
|
tracing::trace!("Multi-select cell data: {}", select_ids.to_string());
|
||||||
Ok(select_ids)
|
select_ids
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
Ok((select_option_ids.to_string(), select_option_ids))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +211,7 @@ mod tests {
|
|||||||
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
|
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
|
||||||
let option_ids = vec![google.id, facebook.id];
|
let option_ids = vec![google.id, facebook.id];
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
|
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
|
||||||
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
|
|
||||||
assert_eq!(&*select_option_ids, &option_ids);
|
assert_eq!(&*select_option_ids, &option_ids);
|
||||||
}
|
}
|
||||||
@ -229,12 +230,12 @@ mod tests {
|
|||||||
|
|
||||||
// insert
|
// insert
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
|
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert_eq!(&*select_option_ids, &option_ids);
|
assert_eq!(&*select_option_ids, &option_ids);
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
let changeset = SelectOptionCellChangeset::from_delete_options(option_ids);
|
let changeset = SelectOptionCellChangeset::from_delete_options(option_ids);
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert!(select_option_ids.is_empty());
|
assert!(select_option_ids.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +251,7 @@ mod tests {
|
|||||||
|
|
||||||
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
|
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_option_id(&google.id);
|
let changeset = SelectOptionCellChangeset::from_insert_option_id(&google.id);
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert_eq!(select_option_ids.to_string(), google.id);
|
assert_eq!(select_option_ids.to_string(), google.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +266,7 @@ mod tests {
|
|||||||
|
|
||||||
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
|
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_option_id(&google.id);
|
let changeset = SelectOptionCellChangeset::from_insert_option_id(&google.id);
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let (_, select_option_ids) = type_option.apply_changeset(changeset, None).unwrap();
|
||||||
assert!(select_option_ids.is_empty());
|
assert!(select_option_ids.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,11 +284,11 @@ mod tests {
|
|||||||
|
|
||||||
// empty option id string
|
// empty option id string
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_option_id("");
|
let changeset = SelectOptionCellChangeset::from_insert_option_id("");
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let (cell_str, _) = type_option.apply_changeset(changeset, None).unwrap();
|
||||||
assert_eq!(select_option_ids.to_string(), "");
|
assert_eq!(cell_str, "");
|
||||||
|
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_option_id("123,456");
|
let changeset = SelectOptionCellChangeset::from_insert_option_id("123,456");
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert!(select_option_ids.is_empty());
|
assert!(select_option_ids.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ pub fn new_select_option_color(options: &Vec<SelectOptionPB>) -> SelectOptionCol
|
|||||||
/// Calls [to_string] will return a string consists list of ids,
|
/// Calls [to_string] will return a string consists list of ids,
|
||||||
/// placing a commas separator between each
|
/// placing a commas separator between each
|
||||||
///
|
///
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct SelectOptionIds(Vec<String>);
|
pub struct SelectOptionIds(Vec<String>);
|
||||||
|
|
||||||
impl SelectOptionIds {
|
impl SelectOptionIds {
|
||||||
|
@ -63,7 +63,7 @@ impl CellDataChangeset for SingleSelectTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
_type_cell_data: Option<TypeCellData>,
|
_type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let mut insert_option_ids = changeset
|
let mut insert_option_ids = changeset
|
||||||
.insert_option_ids
|
.insert_option_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -73,13 +73,14 @@ impl CellDataChangeset for SingleSelectTypeOptionPB {
|
|||||||
// In single select, the insert_option_ids should only contain one select option id.
|
// In single select, the insert_option_ids should only contain one select option id.
|
||||||
// Sometimes, the insert_option_ids may contain list of option ids. For example,
|
// Sometimes, the insert_option_ids may contain list of option ids. For example,
|
||||||
// copy/paste a ids string.
|
// copy/paste a ids string.
|
||||||
if insert_option_ids.is_empty() {
|
let select_option_ids = if insert_option_ids.is_empty() {
|
||||||
Ok(SelectOptionIds::from(insert_option_ids))
|
SelectOptionIds::from(insert_option_ids)
|
||||||
} else {
|
} else {
|
||||||
// Just take the first select option
|
// Just take the first select option
|
||||||
let _ = insert_option_ids.drain(1..);
|
let _ = insert_option_ids.drain(1..);
|
||||||
Ok(SelectOptionIds::from(insert_option_ids))
|
SelectOptionIds::from(insert_option_ids)
|
||||||
}
|
};
|
||||||
|
Ok((select_option_ids.to_string(), select_option_ids))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +196,7 @@ mod tests {
|
|||||||
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
|
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
|
||||||
let option_ids = vec![google.id.clone(), facebook.id];
|
let option_ids = vec![google.id.clone(), facebook.id];
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids);
|
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids);
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert_eq!(&*select_option_ids, &vec![google.id]);
|
assert_eq!(&*select_option_ids, &vec![google.id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,12 +214,12 @@ mod tests {
|
|||||||
|
|
||||||
// insert
|
// insert
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
|
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert_eq!(&*select_option_ids, &vec![google.id]);
|
assert_eq!(&*select_option_ids, &vec![google.id]);
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
let changeset = SelectOptionCellChangeset::from_delete_options(option_ids);
|
let changeset = SelectOptionCellChangeset::from_delete_options(option_ids);
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert!(select_option_ids.is_empty());
|
assert!(select_option_ids.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +232,7 @@ mod tests {
|
|||||||
|
|
||||||
let option_ids = vec![google.id];
|
let option_ids = vec![google.id];
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids);
|
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids);
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
|
|
||||||
assert!(select_option_ids.is_empty());
|
assert!(select_option_ids.is_empty());
|
||||||
}
|
}
|
||||||
@ -243,7 +244,7 @@ mod tests {
|
|||||||
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
|
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
|
||||||
|
|
||||||
let changeset = SelectOptionCellChangeset::from_insert_option_id("");
|
let changeset = SelectOptionCellChangeset::from_insert_option_id("");
|
||||||
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap();
|
let select_option_ids = type_option.apply_changeset(changeset, None).unwrap().1;
|
||||||
assert!(select_option_ids.is_empty());
|
assert!(select_option_ids.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,11 +104,12 @@ impl CellDataChangeset for RichTextTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
_type_cell_data: Option<TypeCellData>,
|
_type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
if changeset.len() > 10000 {
|
if changeset.len() > 10000 {
|
||||||
Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000"))
|
Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000"))
|
||||||
} else {
|
} else {
|
||||||
Ok(StrCellData(changeset))
|
let text_cell_data = StrCellData(changeset);
|
||||||
|
Ok((text_cell_data.to_string(), text_cell_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub trait TypeOption {
|
|||||||
///
|
///
|
||||||
/// Uses `StrCellData` for any `TypeOption` if their cell data is pure `String`.
|
/// Uses `StrCellData` for any `TypeOption` if their cell data is pure `String`.
|
||||||
///
|
///
|
||||||
type CellData: FromCellString + ToString + Default + Send + Sync + Clone + 'static;
|
type CellData: FromCellString + ToString + Default + Send + Sync + Clone + Debug + 'static;
|
||||||
|
|
||||||
/// Represents as the corresponding field type cell changeset.
|
/// Represents as the corresponding field type cell changeset.
|
||||||
/// The changeset must implements the `FromCellChangesetString` and the `ToCellChangesetString` trait.
|
/// The changeset must implements the `FromCellChangesetString` and the `ToCellChangesetString` trait.
|
||||||
|
@ -13,7 +13,7 @@ use flowy_error::FlowyResult;
|
|||||||
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
|
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::Hasher;
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
/// A helper trait that used to erase the `Self` of `TypeOption` trait to make it become a Object-safe trait
|
/// A helper trait that used to erase the `Self` of `TypeOption` trait to make it become a Object-safe trait
|
||||||
/// Only object-safe traits can be made into trait objects.
|
/// Only object-safe traits can be made into trait objects.
|
||||||
@ -55,6 +55,9 @@ struct CellDataCacheKey(u64);
|
|||||||
impl CellDataCacheKey {
|
impl CellDataCacheKey {
|
||||||
pub fn new(field_rev: &FieldRevision, decoded_field_type: FieldType, cell_str: &str) -> Self {
|
pub fn new(field_rev: &FieldRevision, decoded_field_type: FieldType, cell_str: &str) -> Self {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
|
if let Some(type_option_str) = field_rev.get_type_option_str(&decoded_field_type) {
|
||||||
|
type_option_str.hash(&mut hasher);
|
||||||
|
}
|
||||||
hasher.write(field_rev.id.as_bytes());
|
hasher.write(field_rev.id.as_bytes());
|
||||||
hasher.write_u8(decoded_field_type as u8);
|
hasher.write_u8(decoded_field_type as u8);
|
||||||
hasher.write(cell_str.as_bytes());
|
hasher.write(cell_str.as_bytes());
|
||||||
@ -112,7 +115,12 @@ where
|
|||||||
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
|
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
|
||||||
let read_guard = cell_data_cache.read();
|
let read_guard = cell_data_cache.read();
|
||||||
if let Some(cell_data) = read_guard.get(key.as_ref()).cloned() {
|
if let Some(cell_data) = read_guard.get(key.as_ref()).cloned() {
|
||||||
tracing::trace!("Cell cache hit: {}:{}", decoded_field_type, cell_str);
|
tracing::trace!(
|
||||||
|
"Cell cache hit: field_type:{}, cell_str: {}, cell_data: {:?}",
|
||||||
|
decoded_field_type,
|
||||||
|
cell_str,
|
||||||
|
cell_data
|
||||||
|
);
|
||||||
return Ok(cell_data);
|
return Ok(cell_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,12 +132,20 @@ where
|
|||||||
Ok(cell_data)
|
Ok(cell_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_decoded_cell_data(&self, cell_data: <Self as TypeOption>::CellData, field_rev: &FieldRevision) {
|
fn set_decoded_cell_data(
|
||||||
|
&self,
|
||||||
|
cell_str: &str,
|
||||||
|
cell_data: <Self as TypeOption>::CellData,
|
||||||
|
field_rev: &FieldRevision,
|
||||||
|
) {
|
||||||
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
|
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
|
||||||
let field_type: FieldType = field_rev.ty.into();
|
let field_type: FieldType = field_rev.ty.into();
|
||||||
let cell_str = cell_data.to_string();
|
tracing::trace!(
|
||||||
tracing::trace!("Update cell cache {}:{}", field_type, cell_str);
|
"Update cell cache field_type: {}, cell_data: {:?}",
|
||||||
let key = CellDataCacheKey::new(field_rev, field_type, &cell_str);
|
field_type,
|
||||||
|
cell_data
|
||||||
|
);
|
||||||
|
let key = CellDataCacheKey::new(field_rev, field_type, cell_str);
|
||||||
cell_data_cache.write().insert(key.as_ref(), cell_data);
|
cell_data_cache.write().insert(key.as_ref(), cell_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,9 +203,9 @@ where
|
|||||||
field_rev: &FieldRevision,
|
field_rev: &FieldRevision,
|
||||||
) -> FlowyResult<String> {
|
) -> FlowyResult<String> {
|
||||||
let changeset = <Self as TypeOption>::CellChangeset::from_changeset(cell_changeset)?;
|
let changeset = <Self as TypeOption>::CellChangeset::from_changeset(cell_changeset)?;
|
||||||
let cell_data = self.apply_changeset(changeset, old_type_cell_data)?;
|
let (cell_str, cell_data) = self.apply_changeset(changeset, old_type_cell_data)?;
|
||||||
self.set_decoded_cell_data(cell_data.clone(), field_rev);
|
self.set_decoded_cell_data(&cell_str, cell_data, field_rev);
|
||||||
Ok(cell_data.to_string())
|
Ok(cell_str)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_cell_compare(&self, left_cell_data: &str, right_cell_data: &str, field_rev: &FieldRevision) -> Ordering {
|
fn handle_cell_compare(&self, left_cell_data: &str, right_cell_data: &str, field_rev: &FieldRevision) -> Ordering {
|
||||||
|
@ -157,7 +157,7 @@ mod tests {
|
|||||||
expected_url: &str,
|
expected_url: &str,
|
||||||
_field_rev: &FieldRevision,
|
_field_rev: &FieldRevision,
|
||||||
) {
|
) {
|
||||||
let decode_cell_data = type_option.apply_changeset(input_str.to_owned(), None).unwrap();
|
let decode_cell_data = type_option.apply_changeset(input_str.to_owned(), None).unwrap().1;
|
||||||
assert_eq!(expected_str.to_owned(), decode_cell_data.content);
|
assert_eq!(expected_str.to_owned(), decode_cell_data.content);
|
||||||
assert_eq!(expected_url.to_owned(), decode_cell_data.url);
|
assert_eq!(expected_url.to_owned(), decode_cell_data.url);
|
||||||
}
|
}
|
||||||
|
@ -81,15 +81,16 @@ impl CellDataChangeset for URLTypeOptionPB {
|
|||||||
&self,
|
&self,
|
||||||
changeset: <Self as TypeOption>::CellChangeset,
|
changeset: <Self as TypeOption>::CellChangeset,
|
||||||
_type_cell_data: Option<TypeCellData>,
|
_type_cell_data: Option<TypeCellData>,
|
||||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
) -> FlowyResult<(String, <Self as TypeOption>::CellData)> {
|
||||||
let mut url = "".to_string();
|
let mut url = "".to_string();
|
||||||
if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
|
if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
|
||||||
url = auto_append_scheme(m.as_str());
|
url = auto_append_scheme(m.as_str());
|
||||||
}
|
}
|
||||||
Ok(URLCellData {
|
let url_cell_data = URLCellData {
|
||||||
url,
|
url,
|
||||||
content: changeset,
|
content: changeset,
|
||||||
})
|
};
|
||||||
|
Ok((url_cell_data.to_string(), url_cell_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ impl DecodedCellData for URLCellDataPB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct URLCellData {
|
pub struct URLCellData {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
|
@ -142,6 +142,10 @@ impl SortController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn did_update_view_field_type_option(&self, _field_rev: &FieldRevision) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "trace", skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
pub async fn did_receive_changes(&mut self, changeset: SortChangeset) -> SortChangesetNotificationPB {
|
pub async fn did_receive_changes(&mut self, changeset: SortChangeset) -> SortChangesetNotificationPB {
|
||||||
let mut notification = SortChangesetNotificationPB::default();
|
let mut notification = SortChangesetNotificationPB::default();
|
||||||
|
@ -537,6 +537,13 @@ impl GridViewRevisionEditor {
|
|||||||
let new = FilterType::from(&field_rev);
|
let new = FilterType::from(&field_rev);
|
||||||
let filter_type = UpdatedFilterType::new(old, new);
|
let filter_type = UpdatedFilterType::new(old, new);
|
||||||
let filter_changeset = FilterChangeset::from_update(filter_type);
|
let filter_changeset = FilterChangeset::from_update(filter_type);
|
||||||
|
|
||||||
|
self.sort_controller
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.did_update_view_field_type_option(&field_rev)
|
||||||
|
.await;
|
||||||
|
|
||||||
if let Some(changeset) = self
|
if let Some(changeset) = self
|
||||||
.filter_controller
|
.filter_controller
|
||||||
.write()
|
.write()
|
||||||
|
@ -15,7 +15,7 @@ async fn grid_create_field() {
|
|||||||
CreateField { params },
|
CreateField { params },
|
||||||
AssertFieldTypeOptionEqual {
|
AssertFieldTypeOptionEqual {
|
||||||
field_index: test.field_count(),
|
field_index: test.field_count(),
|
||||||
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty).unwrap(),
|
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty).unwrap().to_owned(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
test.run_scripts(scripts).await;
|
test.run_scripts(scripts).await;
|
||||||
@ -25,7 +25,7 @@ async fn grid_create_field() {
|
|||||||
CreateField { params },
|
CreateField { params },
|
||||||
AssertFieldTypeOptionEqual {
|
AssertFieldTypeOptionEqual {
|
||||||
field_index: test.field_count(),
|
field_index: test.field_count(),
|
||||||
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty).unwrap(),
|
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty).unwrap().to_owned(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
test.run_scripts(scripts).await;
|
test.run_scripts(scripts).await;
|
||||||
@ -63,7 +63,7 @@ async fn grid_update_field_with_empty_change() {
|
|||||||
UpdateField { changeset },
|
UpdateField { changeset },
|
||||||
AssertFieldTypeOptionEqual {
|
AssertFieldTypeOptionEqual {
|
||||||
field_index: create_field_index,
|
field_index: create_field_index,
|
||||||
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty).unwrap(),
|
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty).unwrap().to_owned(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
test.run_scripts(scripts).await;
|
test.run_scripts(scripts).await;
|
||||||
|
@ -166,11 +166,16 @@ impl GridRevisionPad {
|
|||||||
Some(field_rev) => {
|
Some(field_rev) => {
|
||||||
let mut_field_rev = Arc::make_mut(field_rev);
|
let mut_field_rev = Arc::make_mut(field_rev);
|
||||||
let old_field_type_rev = mut_field_rev.ty;
|
let old_field_type_rev = mut_field_rev.ty;
|
||||||
let old_field_type_option = mut_field_rev.get_type_option_str(mut_field_rev.ty);
|
let old_field_type_option = mut_field_rev
|
||||||
|
.get_type_option_str(mut_field_rev.ty)
|
||||||
|
.map(|value| value.to_owned());
|
||||||
match mut_field_rev.get_type_option_str(new_field_type) {
|
match mut_field_rev.get_type_option_str(new_field_type) {
|
||||||
Some(new_field_type_option) => {
|
Some(new_field_type_option) => {
|
||||||
let transformed_type_option =
|
let transformed_type_option = type_option_transform(
|
||||||
type_option_transform(old_field_type_rev, old_field_type_option, new_field_type_option);
|
old_field_type_rev,
|
||||||
|
old_field_type_option,
|
||||||
|
new_field_type_option.to_owned(),
|
||||||
|
);
|
||||||
mut_field_rev.insert_type_option_str(&new_field_type, transformed_type_option);
|
mut_field_rev.insert_type_option_str(&new_field_type, transformed_type_option);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
936
shared-lib/Cargo.lock
generated
936
shared-lib/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -165,10 +165,10 @@ impl FieldRevision {
|
|||||||
self.type_options.insert(id, json_str);
|
self.type_options.insert(id, json_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type_option_str<T: Into<FieldTypeRevision>>(&self, field_type: T) -> Option<String> {
|
pub fn get_type_option_str<T: Into<FieldTypeRevision>>(&self, field_type: T) -> Option<&str> {
|
||||||
let field_type_rev = field_type.into();
|
let field_type_rev = field_type.into();
|
||||||
let id = field_type_rev.to_string();
|
let id = field_type_rev.to_string();
|
||||||
self.type_options.get(&id).map(|s| s.to_owned())
|
self.type_options.get(&id).map(|s| s.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user