Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd821b36b2 | ||
|
|
76c642a883 | ||
|
|
e45037c3a7 |
No files matched your search
+5
-8
@@ -97,7 +97,6 @@ class GridURLCell extends GridCellWidget {
|
||||
|
||||
class _GridURLCellState extends GridCellState<GridURLCell> {
|
||||
final _popoverController = PopoverController();
|
||||
GridURLCellController? _cellContext;
|
||||
late URLCellBloc _cellBloc;
|
||||
|
||||
@override
|
||||
@@ -132,6 +131,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
||||
controller: _popoverController,
|
||||
constraints: BoxConstraints.loose(const Size(300, 160)),
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
offset: const Offset(0, 20),
|
||||
child: SizedBox.expand(
|
||||
child: GestureDetector(
|
||||
@@ -144,7 +144,8 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
||||
),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return URLEditorPopover(
|
||||
cellController: _cellContext!,
|
||||
cellController: widget.cellControllerBuilder.build()
|
||||
as GridURLCellController,
|
||||
);
|
||||
},
|
||||
onClose: () {
|
||||
@@ -166,17 +167,13 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
|
||||
final uri = Uri.parse(url);
|
||||
if (url.isNotEmpty && await canLaunchUrl(uri)) {
|
||||
await launchUrl(uri);
|
||||
} else {
|
||||
_cellContext =
|
||||
widget.cellControllerBuilder.build() as GridURLCellController;
|
||||
widget.onCellEditing.value = true;
|
||||
_popoverController.show();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void requestBeginFocus() {
|
||||
_openUrlOrEdit(_cellBloc.state.url);
|
||||
widget.onCellEditing.value = true;
|
||||
_popoverController.show();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -210,7 +210,7 @@ impl ViewController {
|
||||
let index = views
|
||||
.iter()
|
||||
.position(|view| view.id == view_id)
|
||||
.and_then(|index| Some(index as i32));
|
||||
.map(|index| index as i32);
|
||||
Ok(DeletedViewPB {
|
||||
view_id: view_id.clone(),
|
||||
index,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::entities::FieldType;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
@@ -74,15 +75,20 @@ pub struct GridCellPB {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
|
||||
// The data was encoded in field_type's data type
|
||||
#[pb(index = 2)]
|
||||
pub data: Vec<u8>,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub field_type: Option<FieldType>,
|
||||
}
|
||||
|
||||
impl GridCellPB {
|
||||
pub fn new(field_id: &str, data: Vec<u8>) -> Self {
|
||||
pub fn new(field_id: &str, field_type: FieldType, data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
field_id: field_id.to_owned(),
|
||||
data,
|
||||
field_type: Some(field_type),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +96,7 @@ impl GridCellPB {
|
||||
Self {
|
||||
field_id: field_id.to_owned(),
|
||||
data: vec![],
|
||||
field_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,28 @@ pub trait CellDisplayable<CD> {
|
||||
decoded_field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<CellBytes>;
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<CD>,
|
||||
decoded_field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String>;
|
||||
}
|
||||
|
||||
// CD: Short for CellData. This type is the type return by apply_changeset function.
|
||||
// CS: Short for Changeset. Parse the string into specific Changeset type.
|
||||
pub trait CellDataOperation<CD, CS> {
|
||||
/// The cell_data is able to parse into the specific data if CD impl the FromCellData trait.
|
||||
/// For example:
|
||||
/// URLCellData, DateCellData. etc.
|
||||
/// Decode the cell data into `CD` that is certain type of data.
|
||||
///
|
||||
/// Each `CD` type represents as a specific field type data. For example:
|
||||
/// FieldType::URL => URLCellData
|
||||
/// FieldType::Date=> DateCellData
|
||||
///
|
||||
/// `decoded_field_type`: the field type of the cell data
|
||||
///
|
||||
/// Returns the error if the cell data can't be parsed into `CD`.
|
||||
///
|
||||
fn decode_cell_data(
|
||||
&self,
|
||||
cell_data: CellData<CD>,
|
||||
@@ -77,16 +91,16 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
|
||||
pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>(
|
||||
data: T,
|
||||
field_rev: &FieldRevision,
|
||||
) -> CellBytes {
|
||||
) -> (FieldType, CellBytes) {
|
||||
let to_field_type = field_rev.ty.into();
|
||||
match data.try_into() {
|
||||
Ok(any_cell_data) => {
|
||||
let AnyCellData { data, field_type } = any_cell_data;
|
||||
let to_field_type = field_rev.ty.into();
|
||||
match try_decode_cell_data(data.into(), field_rev, &field_type, &to_field_type) {
|
||||
Ok(cell_bytes) => cell_bytes,
|
||||
match try_decode_cell_data(data.into(), &field_type, &to_field_type, field_rev) {
|
||||
Ok(cell_bytes) => (field_type, cell_bytes),
|
||||
Err(e) => {
|
||||
tracing::error!("Decode cell data failed, {:?}", e);
|
||||
CellBytes::default()
|
||||
(field_type, CellBytes::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,42 +108,93 @@ pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>
|
||||
// It's okay to ignore this error, because it's okay that the current cell can't
|
||||
// display the existing cell data. For example, the UI of the text cell will be blank if
|
||||
// the type of the data of cell is Number.
|
||||
CellBytes::default()
|
||||
|
||||
(to_field_type, CellBytes::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_cell_data_to_string(
|
||||
cell_data: CellData<String>,
|
||||
from_field_type: &FieldType,
|
||||
to_field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
let cell_data = cell_data.try_into_inner()?;
|
||||
let get_cell_display_str = || {
|
||||
let field_type: FieldTypeRevision = to_field_type.into();
|
||||
let result = match to_field_type {
|
||||
FieldType::RichText => field_rev
|
||||
.get_type_option::<RichTextTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::Number => field_rev
|
||||
.get_type_option::<NumberTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::DateTime => field_rev
|
||||
.get_type_option::<DateTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::SingleSelect => field_rev
|
||||
.get_type_option::<SingleSelectTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::MultiSelect => field_rev
|
||||
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::Checkbox => field_rev
|
||||
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::URL => field_rev
|
||||
.get_type_option::<URLTypeOptionPB>(field_type)?
|
||||
.display_string(cell_data.into(), from_field_type, field_rev),
|
||||
};
|
||||
Some(result)
|
||||
};
|
||||
|
||||
match get_cell_display_str() {
|
||||
Some(Ok(s)) => Ok(s),
|
||||
Some(Err(err)) => {
|
||||
tracing::error!("{:?}", err);
|
||||
Ok("".to_owned())
|
||||
}
|
||||
None => Ok("".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Use the `to_field_type`'s TypeOption to parse the cell data into `from_field_type` type's data.
|
||||
///
|
||||
/// Each `FieldType` has its corresponding `TypeOption` that implements the `CellDisplayable`
|
||||
/// and `CellDataOperation` traits.
|
||||
///
|
||||
pub fn try_decode_cell_data(
|
||||
cell_data: CellData<String>,
|
||||
from_field_type: &FieldType,
|
||||
to_field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
s_field_type: &FieldType,
|
||||
t_field_type: &FieldType,
|
||||
) -> FlowyResult<CellBytes> {
|
||||
let cell_data = cell_data.try_into_inner()?;
|
||||
let get_cell_data = || {
|
||||
let field_type: FieldTypeRevision = t_field_type.into();
|
||||
let data = match t_field_type {
|
||||
let field_type: FieldTypeRevision = to_field_type.into();
|
||||
let data = match to_field_type {
|
||||
FieldType::RichText => field_rev
|
||||
.get_type_option::<RichTextTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::Number => field_rev
|
||||
.get_type_option::<NumberTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::DateTime => field_rev
|
||||
.get_type_option::<DateTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::SingleSelect => field_rev
|
||||
.get_type_option::<SingleSelectTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::MultiSelect => field_rev
|
||||
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::Checkbox => field_rev
|
||||
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
FieldType::URL => field_rev
|
||||
.get_type_option::<URLTypeOptionPB>(field_type)?
|
||||
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||
};
|
||||
Some(data)
|
||||
};
|
||||
@@ -224,6 +289,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<usize> for CellData<String> {
|
||||
fn from(n: usize) -> Self {
|
||||
CellData(Some(n.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::convert::From<T> for CellData<T> {
|
||||
fn from(val: T) -> Self {
|
||||
CellData(Some(val))
|
||||
|
||||
+10
@@ -48,6 +48,16 @@ impl CellDisplayable<CheckboxCellData> for CheckboxTypeOptionPB {
|
||||
let cell_data = cell_data.try_into_inner()?;
|
||||
Ok(CellBytes::new(cell_data))
|
||||
}
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<CheckboxCellData>,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
let cell_data = cell_data.try_into_inner()?;
|
||||
Ok(cell_data.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<CheckboxCellData, String> for CheckboxTypeOptionPB {
|
||||
|
||||
+11
@@ -127,6 +127,17 @@ impl CellDisplayable<DateTimestamp> for DateTypeOptionPB {
|
||||
let date_cell_data = self.today_desc_from_timestamp(timestamp);
|
||||
CellBytes::from(date_cell_data)
|
||||
}
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<DateTimestamp>,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
let timestamp = cell_data.try_into_inner()?;
|
||||
let date_cell_data = self.today_desc_from_timestamp(timestamp);
|
||||
Ok(date_cell_data.date)
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOptionPB {
|
||||
|
||||
+29
-8
@@ -1,6 +1,6 @@
|
||||
use crate::entities::FieldType;
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation};
|
||||
use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
|
||||
use crate::services::field::type_options::number_type_option::format::*;
|
||||
use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBuilder};
|
||||
use bytes::Bytes;
|
||||
@@ -102,17 +102,13 @@ pub(crate) fn strip_currency_symbol<T: ToString>(s: T) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
impl CellDataOperation<String, String> for NumberTypeOptionPB {
|
||||
fn decode_cell_data(
|
||||
impl CellDisplayable<String> for NumberTypeOptionPB {
|
||||
fn display_data(
|
||||
&self,
|
||||
cell_data: CellData<String>,
|
||||
decoded_field_type: &FieldType,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<CellBytes> {
|
||||
if decoded_field_type.is_date() {
|
||||
return Ok(CellBytes::default());
|
||||
}
|
||||
|
||||
let cell_data: String = cell_data.try_into_inner()?;
|
||||
match self.format_cell_data(&cell_data) {
|
||||
Ok(num) => Ok(CellBytes::new(num.to_string())),
|
||||
@@ -120,6 +116,31 @@ impl CellDataOperation<String, String> for NumberTypeOptionPB {
|
||||
}
|
||||
}
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<String>,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
let cell_data: String = cell_data.try_into_inner()?;
|
||||
Ok(cell_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<String, String> for NumberTypeOptionPB {
|
||||
fn decode_cell_data(
|
||||
&self,
|
||||
cell_data: CellData<String>,
|
||||
decoded_field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<CellBytes> {
|
||||
if decoded_field_type.is_date() {
|
||||
return Ok(CellBytes::default());
|
||||
}
|
||||
|
||||
self.display_data(cell_data, decoded_field_type, field_rev)
|
||||
}
|
||||
|
||||
fn apply_changeset(
|
||||
&self,
|
||||
changeset: CellDataChangeset<String>,
|
||||
|
||||
+15
@@ -120,6 +120,21 @@ where
|
||||
) -> FlowyResult<CellBytes> {
|
||||
CellBytes::from(self.selected_select_option(cell_data))
|
||||
}
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<SelectOptionIds>,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
Ok(self
|
||||
.selected_select_option(cell_data)
|
||||
.select_options
|
||||
.into_iter()
|
||||
.map(|option| option.name)
|
||||
.collect::<Vec<String>>()
|
||||
.join(SELECTION_IDS_SEPARATOR))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult<Box<dyn SelectOptionOperation>> {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
mod text_tests;
|
||||
mod text_type_option;
|
||||
|
||||
pub use text_type_option::*;
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataOperation;
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::*;
|
||||
|
||||
// Test parser the cell data which field's type is FieldType::Date to cell data
|
||||
// which field's type is FieldType::Text
|
||||
#[test]
|
||||
fn date_type_to_text_type() {
|
||||
let type_option = RichTextTypeOptionPB::default();
|
||||
let field_type = FieldType::DateTime;
|
||||
let field_rev = FieldBuilder::from_field_type(&field_type).build();
|
||||
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_data(1647251762.into(), &field_type, &field_rev)
|
||||
.unwrap()
|
||||
.parser::<TextCellDataParser>()
|
||||
.unwrap()
|
||||
.as_ref(),
|
||||
"Mar 14,2022"
|
||||
);
|
||||
}
|
||||
|
||||
// Test parser the cell data which field's type is FieldType::SingleSelect to cell data
|
||||
// which field's type is FieldType::Text
|
||||
#[test]
|
||||
fn single_select_to_text_type() {
|
||||
let type_option = RichTextTypeOptionPB::default();
|
||||
|
||||
let field_type = FieldType::SingleSelect;
|
||||
let done_option = SelectOptionPB::new("Done");
|
||||
let option_id = done_option.id.clone();
|
||||
let single_select = SingleSelectTypeOptionBuilder::default().add_option(done_option.clone());
|
||||
let field_rev = FieldBuilder::new(single_select).build();
|
||||
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_data(option_id.into(), &field_type, &field_rev)
|
||||
.unwrap()
|
||||
.parser::<TextCellDataParser>()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
done_option.name,
|
||||
);
|
||||
}
|
||||
}
|
||||
+29
-85
@@ -1,8 +1,8 @@
|
||||
use crate::entities::FieldType;
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{
|
||||
try_decode_cell_data, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataOperation, CellDisplayable,
|
||||
FromCellString,
|
||||
decode_cell_data_to_string, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataOperation,
|
||||
CellDisplayable, FromCellString,
|
||||
};
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
use bytes::Bytes;
|
||||
@@ -44,6 +44,16 @@ impl CellDisplayable<String> for RichTextTypeOptionPB {
|
||||
let cell_str: String = cell_data.try_into_inner()?;
|
||||
Ok(CellBytes::new(cell_str))
|
||||
}
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<String>,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
let cell_str: String = cell_data.try_into_inner()?;
|
||||
Ok(cell_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<String, String> for RichTextTypeOptionPB {
|
||||
@@ -57,8 +67,10 @@ impl CellDataOperation<String, String> for RichTextTypeOptionPB {
|
||||
|| decoded_field_type.is_single_select()
|
||||
|| decoded_field_type.is_multi_select()
|
||||
|| decoded_field_type.is_number()
|
||||
|| decoded_field_type.is_url()
|
||||
{
|
||||
try_decode_cell_data(cell_data, field_rev, decoded_field_type, decoded_field_type)
|
||||
let s = decode_cell_data_to_string(cell_data, decoded_field_type, decoded_field_type, field_rev);
|
||||
Ok(CellBytes::new(s.unwrap_or_else(|_| "".to_owned())))
|
||||
} else {
|
||||
self.display_data(cell_data, decoded_field_type, field_rev)
|
||||
}
|
||||
@@ -85,6 +97,14 @@ impl AsRef<str> for TextCellData {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for TextCellData {
|
||||
type Target = String;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCellString for TextCellData {
|
||||
fn from_cell_str(s: &str) -> FlowyResult<Self>
|
||||
where
|
||||
@@ -94,6 +114,12 @@ impl FromCellString for TextCellData {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for TextCellData {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextCellDataParser();
|
||||
impl CellBytesParser for TextCellDataParser {
|
||||
type Object = TextCellData;
|
||||
@@ -104,85 +130,3 @@ impl CellBytesParser for TextCellDataParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataOperation;
|
||||
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::*;
|
||||
|
||||
#[test]
|
||||
fn text_description_test() {
|
||||
let type_option = RichTextTypeOptionPB::default();
|
||||
|
||||
// date
|
||||
let field_type = FieldType::DateTime;
|
||||
let date_time_field_rev = FieldBuilder::from_field_type(&field_type).build();
|
||||
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_data(1647251762.to_string().into(), &field_type, &date_time_field_rev)
|
||||
.unwrap()
|
||||
.parser::<DateCellDataParser>()
|
||||
.unwrap()
|
||||
.date,
|
||||
"Mar 14,2022".to_owned()
|
||||
);
|
||||
|
||||
// Single select
|
||||
let done_option = SelectOptionPB::new("Done");
|
||||
let done_option_id = done_option.id.clone();
|
||||
let single_select = SingleSelectTypeOptionBuilder::default().add_option(done_option.clone());
|
||||
let single_select_field_rev = FieldBuilder::new(single_select).build();
|
||||
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_data(
|
||||
done_option_id.into(),
|
||||
&FieldType::SingleSelect,
|
||||
&single_select_field_rev
|
||||
)
|
||||
.unwrap()
|
||||
.parser::<SelectOptionCellDataParser>()
|
||||
.unwrap()
|
||||
.select_options,
|
||||
vec![done_option],
|
||||
);
|
||||
|
||||
// Multiple select
|
||||
let google_option = SelectOptionPB::new("Google");
|
||||
let facebook_option = SelectOptionPB::new("Facebook");
|
||||
let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
|
||||
let cell_data_changeset = SelectOptionCellChangeset::from_insert(&ids).to_str();
|
||||
let multi_select = MultiSelectTypeOptionBuilder::default()
|
||||
.add_option(google_option.clone())
|
||||
.add_option(facebook_option.clone());
|
||||
let multi_select_field_rev = FieldBuilder::new(multi_select).build();
|
||||
let multi_type_option = MultiSelectTypeOptionPB::from(&multi_select_field_rev);
|
||||
let cell_data = multi_type_option
|
||||
.apply_changeset(cell_data_changeset.into(), None)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_data(cell_data.into(), &FieldType::MultiSelect, &multi_select_field_rev)
|
||||
.unwrap()
|
||||
.parser::<SelectOptionCellDataParser>()
|
||||
.unwrap()
|
||||
.select_options,
|
||||
vec![google_option, facebook_option]
|
||||
);
|
||||
|
||||
//Number
|
||||
let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD);
|
||||
let number_field_rev = FieldBuilder::new(number).build();
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_data("18443".to_owned().into(), &FieldType::Number, &number_field_rev)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
"$18,443".to_owned()
|
||||
);
|
||||
}
|
||||
}
|
||||
+10
@@ -42,6 +42,16 @@ impl CellDisplayable<URLCellDataPB> for URLTypeOptionPB {
|
||||
let cell_data: URLCellDataPB = cell_data.try_into_inner()?;
|
||||
CellBytes::from(cell_data)
|
||||
}
|
||||
|
||||
fn display_string(
|
||||
&self,
|
||||
cell_data: CellData<URLCellDataPB>,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<String> {
|
||||
let cell_data: URLCellDataPB = cell_data.try_into_inner()?;
|
||||
Ok(cell_data.content)
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<URLCellDataPB, String> for URLTypeOptionPB {
|
||||
|
||||
@@ -435,14 +435,18 @@ impl GridRevisionEditor {
|
||||
}
|
||||
|
||||
pub async fn get_cell(&self, params: &GridCellIdParams) -> Option<GridCellPB> {
|
||||
let cell_bytes = self.get_cell_bytes(params).await?;
|
||||
Some(GridCellPB::new(¶ms.field_id, cell_bytes.to_vec()))
|
||||
let (field_type, cell_bytes) = self.decode_any_cell_data(params).await?;
|
||||
Some(GridCellPB::new(¶ms.field_id, field_type, cell_bytes.to_vec()))
|
||||
}
|
||||
|
||||
pub async fn get_cell_bytes(&self, params: &GridCellIdParams) -> Option<CellBytes> {
|
||||
let (_, cell_data) = self.decode_any_cell_data(params).await?;
|
||||
Some(cell_data)
|
||||
}
|
||||
|
||||
async fn decode_any_cell_data(&self, params: &GridCellIdParams) -> Option<(FieldType, CellBytes)> {
|
||||
let field_rev = self.get_field_rev(¶ms.field_id).await?;
|
||||
let row_rev = self.block_manager.get_row_rev(¶ms.row_id).await.ok()??;
|
||||
|
||||
let cell_rev = row_rev.cells.get(¶ms.field_id)?.clone();
|
||||
Some(decode_any_cell_data(cell_rev.data, &field_rev))
|
||||
}
|
||||
|
||||
@@ -201,6 +201,10 @@ impl GridViewRevisionEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn group_id(&self) -> String {
|
||||
self.group_controller.read().await.field_id().to_owned()
|
||||
}
|
||||
|
||||
pub(crate) async fn get_setting(&self) -> GridSettingPB {
|
||||
let field_revs = self.field_delegate.get_field_revs().await;
|
||||
let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs);
|
||||
|
||||
@@ -178,12 +178,16 @@ impl GridViewManager {
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub(crate) async fn did_update_field(&self, field_id: &str, is_type_option_changed: bool) -> FlowyResult<()> {
|
||||
let view_editor = self.get_default_view_editor().await?;
|
||||
// Only the field_id of the updated field is equal to the field_id of the group.
|
||||
// Update the group
|
||||
if view_editor.group_id().await != field_id {
|
||||
return Ok(());
|
||||
}
|
||||
if is_type_option_changed {
|
||||
let _ = view_editor.group_by_field(field_id).await?;
|
||||
} else {
|
||||
let _ = view_editor.did_update_field(field_id).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ where
|
||||
|
||||
if let Some(cell_rev) = cell_rev {
|
||||
let mut grouped_rows: Vec<GroupedRow> = vec![];
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev);
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev).1;
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
for group in self.group_ctx.groups() {
|
||||
if self.can_group(&group.filter_content, &cell_data) {
|
||||
@@ -244,7 +244,7 @@ where
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<Vec<GroupChangesetPB>> {
|
||||
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1;
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
let mut changesets = self.add_row_if_match(row_rev, &cell_data);
|
||||
let default_group_changeset = self.update_default_group(row_rev, &changesets);
|
||||
@@ -265,7 +265,7 @@ where
|
||||
) -> FlowyResult<Vec<GroupChangesetPB>> {
|
||||
// if the cell_rev is none, then the row must be crated from the default group.
|
||||
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1;
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
Ok(self.remove_row_if_match(row_rev, &cell_data))
|
||||
} else {
|
||||
@@ -285,7 +285,7 @@ where
|
||||
};
|
||||
|
||||
if let Some(cell_rev) = cell_rev {
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data, context.field_rev);
|
||||
let cell_bytes = decode_any_cell_data(cell_rev.data, context.field_rev).1;
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
Ok(self.move_row(&cell_data, context))
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user